Scrolling text on an 8x8 LEDS display

published: 22 June 2019 / updated 30 June 2019

Lire cette page en français

 


Characters definition

We mean by character, any binary set written in an 8x8 square. This 8x8 dimension is the one we have in the 8x8 LED matrix display.

The orientation imposed on our 8x8 LED array is with the input connectors facing down:

8x8 LED matrix with downward-facing input connectors

This orientation makes it possible to connect other 8x8 LED arrays by placing them on the right or on the left, allowing thus manage a display of nx8x8 LEDs. With 4 8x8 LED dies, you can display a text or drawing on a super matrix of 32x8 LEDs. Orifices are provided on the printed circuit, orifices allowing the fixing matrix displays on a stable and visible support. The ARDUINO card must stay as close to matrix displays with LEDs.

LED display organization 8x8

Each column corresponds to an address, numbered from 1 to 8. Sending a value between 0 and 255 in a column, ie at an address, will display this value in binary form. In the case of the smiley, the first value will be %00100000, which is 32 in decimal, $20 in hexadecimal. The fact Entering the values in binary allows you to have an immediate overview of the pattern to display.

SMILEY character definition

In our previous article (The SPI interface: management of an 8x8 LEDS display) we were displaying a smiley character with the word disp-test-3, a word we rewritten by straightening the smiley in the word disp-test-4. But the definition of the word disp-test-4 is not satisfactory, because it would be necessary to write a word by character to display.

We will isolate the binary code to display the smiley in a table:

\ Mikael Nordman write: 
\ Since you have been using flash create there is no need for ic,
\ c, will store to flash anyway.
flash
create SMILEY ( --- addr)
    %00100000 c,
    %01000010 c,
    %10000010 c,
    %10011000 c,
    %10011000 c,
    %10000010 c,
    %01000010 c,
    %00100000 c,

The word SMILEY stacks the address of the first byte compiled here%00100000 c,:

SMILEY c@   \ empile %00100000 soit 32 en décimal, $20 en hexadécimal

To access the other bytes, simply increment the address stacked by SMILEY:

SMILEY 1 + c@   \ empile %01000010 
SMILEY 2 + c@   \ empile %10000010 
SMILEY 3 + c@   \ empile %10011000
\ ...etc...

To extract all the bytes defined in SMILEY, it suffices to to make an iterative loop defined:

: disp.char ( addr ---)
    1-                  \ decrement array address
    8 for
        1+ dup c@       \ increment address, duplicate and get value
        8 r@ -          \ get loop index, numbering 1 to 8
        swap max7219.send
    next
    drop                \ drop array address
    ;

The word disp.char needs the start address of the array containing the bytes defining a drawing or character to display:

SMILEY disp.char

 WARNING  This may not work if the SPI interface is not initialized. This is what we will do with this word:

: smiley-disp ( ---)
    spi.init
    disp.normal
    $01 disp.intensity
    $07 disp.scan.limit
    SMILEY disp.char
    begin key? until
    disp.shutdown
    spi.close
;

Now you can run smiley-disp, which will show the smiley on the 8x8 LED display.

Scrolling smiley display

flash
create SMILEYsprite ( --- addr)
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00100000 c,
    %01000010 c,
    %10000010 c,
    %10011000 c,
    %10011000 c,
    %10000010 c,
    %01000010 c,
    %00100000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
    %00000000 c,
 
: sprite-scroll ( addr ---)
    1-                  \ decrement array address
    16 for   
        1+ dup          \ increment address, duplicate and get value
        disp.char
        200 ms
    next 
    drop                \ drop array address
;
 
: disp-scroll ( ---)
    spi.init
    disp.normal
    $01 disp.intensity
    $07 disp.scan.limit
    begin 
        SMILEYsprite sprite-scroll
    key? until
    disp.shutdown
    spi.close
;

Definition of alphanumeric characters

We defined a smiley character through the SMILEY table. Now, we will create a table that will contain all alphanumeric characters. Let's start with see how to encode the character "0" (zero):

Character definition '0'
  1. we draw the character '0' in a square of 8x8 squares
  2. you turn the character clockwise 90 °
  3. we encode in binary or hexadecimal each line of the 8x8 square

What gives in FORTH:

\ caracters 0..9A..Z in array
flash
create CHARACTERS
    $00 c, $00 c, $00 c, $00 c, 
    $00 c, $00 c, $00 c, $00 c,     \  U+0020 (space)
    $00 c, $00 c, $00 c, $00 c,
    $bf c, $00 c, $00 c, $00 c,     \  U+0021 (!1 tst)
    $00 c, $00 c, $03 c, $00 c, 
    $03 c, $00 c, $00 c, $00 c,     \  U+0022 (")
    $00 c, $24 c, $ff c, $24 c, 
    $24 c, $ff c, $24 c, $00 c,     \  U+0023 (#)
        \ <CUT> ......
    $89 c, $85 c, $7e c, $00 c,     \  U+0030 (0) (16)
    $00 c, $00 c, $00 c, $04 c, 
    $82 c, $ff c, $80 c, $00 c,     \  U+0031 (1)
    $00 c, $e2 c, $91 c, $91 c, 
    $91 c, $91 c, $8e c, $00 c,     \  U+0032 (2)
    $00 c, $42 c, $81 c, $89 c, 
    $89 c, $89 c, $76 c, $00 c,     \  U+0033 (3)
    $00 c, $0f c, $08 c, $08 c, 
    $08 c, $08 c, $ff c, $00 c,     \  U+0034 (4)
        \ <CUT> ......
    $11 c, $11 c, $fe c, $00 c,     \  U+0041 (A)
    $00 c, $ff c, $89 c, $89 c, 
    $89 c, $89 c, $76 c, $00 c,     \  U+0042 (B)
    $00 c, $7e c, $81 c, $81 c, 
    $81 c, $81 c, $42 c, $00 c,     \  U+0043 (C)
    $00 c, $ff c, $81 c, $81 c, 
    $81 c, $81 c, $7e c, $00 c,     \  U+0044 (D)
    $00 c, $ff c, $89 c, $89 c, 
    $89 c, $89 c, $81 c, $00 c,     \  U+0045 (E)
    $00 c, $ff c, $09 c, $09 c, 
        \ <CUT> ......

full listing here.

In this table, we have compiled the matrix representation of the characters ASCII between space and Z. We will create a word to test the character display of this table on the 8x8 LED display:

: getChar ( n ---)          \ get nth caracters from CHARACTERS table
    8 * CHARACTERS + ;
 
: Cdisp ( n ---)            \ display character on 8x8 LED matrix
    spi.init
    disp.normal
    $01 disp.intensity
    $07 disp.scan.limit
    getChar disp.char
    begin key? until
    disp.shutdown
    spi.close  ;
 
: Cled ( char ---)          \ typical use: char B Cled 
    32 - Cdisp ;

This is the word Cled that interests us:/p>

char ! Cled  \ display '!' on 8x8 LED matrix
char A Cled  \ display 'A'
char Z Cled  \ display 'Z'

Scroll a text

We will now exploit our character matrix table to handle scrolling text on the 8x8 LED display. Of course, it would have been much better to have several matrices LED 8x8, but as I have only one display, we will do with what we have.

The first thing to do is to create a scrollBuffer buffer that will host the text in its matrix form:

ram create scrollBuffer
   18 8 * allot

This array scrollBuffer can accommodate a text of 18 characters, in reality 16 characters at the most, because it will be necessary to foresee the space character at the beginning and the end text.

Here is how to store each character in this buffer scrollBuffer:

variable inCharBuffer   \ pointer nth char
 
: charToBuffer ( char ---) \ copy a matric char in buffer
    32 - getChar        \ calculate start address
    scrollBuffer inCharBuffer @ 8 * + \ calculate destination address
    8 cmove             \ copy char matric
    1 inCharBuffer +!   \ increment buffer storage pointer
    ;

The word charToBuffer retrieves the ASCII code of the character to insert in the scrollBuffer array. He's going to get the matrix table 8x8 of the character to be copied and inserts it at position n * 8, where n is the value of the index insert inCharBuffer.

Now let's see how to handle an entire text:

: text-in-buffer ( adr len ---)
    0 inCharBuffer !    \ initialise buffer storage pointer
    32 charToBuffer     \ copy 'space' matrix in buffer
    dup                 \ duplicate len
    for
        2dup            \ duplicate adr len
        r@ 1+ - +       \ calculate adr char by char
        c@              \ get char in input string (adr len)
        charToBuffer    \ copy matric char in buffer
    next
    2drop
    32 charToBuffer     \ copy 'space' matrix in buffer
    ;

The word text-in-buffer initializes the insertion index.

Then he inserts a space character.

Then the for..next loop processes the contents of a past string as a parameter to text-in-buffer to process this string character by character.

At the end of the loop, insert a space character again.

We will now manage the display of the content of the buffer scrollBuffer to the 8x8 LED matrix:

: text-scroll ( ---)
    scrollBuffer 1-     \ decrement scroll buffer address
    inCharBuffer @ 1- 8 * for   
        1+ dup          \ increment address, duplicate and get value
        disp.char
        200 ms
    next 
    drop                \ drop array address
;

This word text-scroll once only closes the display of the content of scrollBuffer.

Here's how to display FORTH in scrolling text on the 8x8 LED array:

: sFORTH ( --- adr len)
    s" FORTH" ;
 
: txt.scroll ( adr len ---)  \ example sFORTH txt-scroll
    text-in-buffer
    spi.init
    disp.normal
    $01 disp.intensity
    $07 disp.scan.limit
    begin 
        text-scroll
    key? until
    disp.shutdown
    spi.close
;

The word sFORTH (for string FORTH) serves as the constant of text. Its execution stacks the address and the length of the text "FORTH" to display:

sFORTH txt.scroll

Result in video: