bclose

45 – 8×8 LED MATRIX

Objectives

 

 

    • Introduce the 8×8 LED matrices.
    • Assemble a prototype.
    • Program a moving message.
 

BILL OF MATERIALS

Arduino UNO

Arduino UNO or equivalent.

BreadboardJumper wires A solderless Breadboard plus some jumper wires.
330 Ohm resistor

8 x 330 Ω resistors.

LED dot matrix

A 1588AS or 1388ASR 8×8 LED matrix

LED MATRICES

 

It seems that LEDs are manufactured in all sizes and formats imaginable and this component, that we present today, is proud of that creativity. Arrays of LEDs (or LED arrays) are, as the name suggests, arrays of standard LEDs that are sold in multiple formats and colors. From a single color, to those which have several possible colors, and there is even an RGB LED matrix (imagine how many pins it has).

In this chapter, our Arduino tutorial, we will use an 8 × 8 red LED array. I hope it can serve as a demonstration of how to handle them and what can be done with this kind of material. We will use a single array and we will drag letters and symbols to show what we could do with a dozen of these friendly displays.

The idea is that, as we have a 8 × 8 matrix, we can draw letters and symbols in the same way that we did in the past, when we defined the degree symbol for the LCD display. That is, we will define dot arrays to represent characters to later draw them on the display.

LED dot matrix

LED dot matrix diagram

Moreover, they are completely normal LED diodes organized in the shape of a matrix, that we will have to multiplex to turn up one dot or another, as we did in the chapter on the matrix keyboard. On the back side of this component you can see 2 pin strips of 8 pins each, which are connected to the rows and columns of the dot matrix.

 
  • If the diodes are joined by the positive side they are said to be common anode matrices (the pedantic name for positive) and if they are joined by the negative side they are said to be common cathode matrices.
  • Depending on the manufacturer we can find both..  

If we set a column HIGH, let’s say the second one, nothing will be illuminated yet. But when we set a row LOW, let’s say the fourth row, the circuit will be closed to GND (via a limiting resistor, of course) and the LED dot on column 2 and row 4 will turn up.

If you believed that the 8 rows and 8 columns of the matrix correspond to the two pin strips, where a pin strip corresponds to the columns and the other to rows, (the logical thing, right?), you would be wrong. Because this is one of those cases where the manufacturer, due to inscrutable reasons for ordinary mortals, has decided to mix one and the other at random, making almost impossible to guess which is which without the manual and making wiring become a nightmare.

So, apply rule number one. Look for the manufacturer’s manual or data sheet in Google (it’s easier than you think).

 
  • By the way, in Internet you will find very often the following: “Read the manual first!”. In fact, they have even coined an acronym for it: RTFM, initials of a nice phrase, that I will avoid to translate. 

So, let’s go with the data sheet of the 1588AS:1588AS data sheet

Note that here the important thing is, the description of the matrix, where it speaks about the rows and columns, but above all it tells us which pins are dedicated to each row and column. Now we only need to know which of the pins is the first one, and here, I have not been able to locate a mark showing it. In spite of the fact that the manual marks with a cross the pin 1, I have not been able to find any asymmetric brand in my own chip.

 
  • What I have done is to connect 5V and GND via a 330 Ω resistor, and look for the pins 13 and 9, which correspond to column 1 and row 1, until the dot 1.1 lit up. From there onwards, the rest is easy. 

I recommend you that once you locate it, keep connecting the rest of the pins slowly and testing the connections. In my case I connected the columns as follows:

Dot Matrix 13 3 4 10 6 11 15 16
Arduino 2 3 4 5 6 7 8 9

And these are the connections for the rows:

Dot Matrix 9 14 8 12 1 7 2 5
Arduino 10 11 12 13 A0 A1 A2 A3

 

If you are one of those who use the new starter kit from PROMETEC, the display is a 1388ASR, which is a common anode model, the arrangement of pins is different and its definition is the following:

1388ASR pinout

 

The connection to your Arduino is as follows:

Dot Matrix 1 2 6 11 7 13 14 4
Arduino 2 3 4 5 6 7 8 9

And this is for the rows:

Dot Matrix 12 15 10 16 5 9 3 8
Arduino 10 11 12 13 A0 A1 A2 A3

Note that, as we connect the same layout of rows and columns to our Arduino and using the same pin order, the configuration is interchangeable.

Here you have a program that sweeps the matrix and helps you to check the connections.

Sketch 45.1

 

I think this will be the first, and hopefully last time, that we will not include a schematic or wiring diagram to show the connections because I have not found any matrix like this in Fritzing and because I think it would add very little to the tables above.

THE CONTROL PROGRAM

 

The sweeping program we have used to prove that we had properly connected the dots, contains the basis of our control program.

void setup()                           
   {   
        for (int j=2; j<19; j++)
            pinMode(j, OUTPUT);
   }

void loop() 
{
  for (int j=2; j<10; j++)
    {
        digitalWrite(j, HIGH);     // We set the row to HIGH 
        for (int k= 10 ; k

The important thing in it is, first, that we define inside the setup() function the pins from 2 to 19 as output pins.
Pin 19?. There are not so many pins!. Well, actually yes.

We saw, at the time, that the analog pins from A0 to A5 could be used as normal digital pins. So, if needed, we can use them as digital pins, numbered from 14 to 19.

I have taken advantage of this curiosity, to make it more comfortable to write the sketch. To turn up a specific dot, first set LOW all columns and HIGH all rows, which turns off everything.

Later you will have to set HIGH the column containing the dot to be lit up. Note that this, in itself, will not turn up anything yet. As soon as we set one of the rows LOW, the circuit will be closed and a dot will lit up. The curiosity of this is that the diode lights when we put 0 in a row, not 1 as before.

This is called, negative logic, because the action is executed using a low value, not a high one.

So how do we display a character, say P? Well, as we saw in the previous chapter, by drawing squares on a squared paper.

But, then, do we need to define a matrix for each letter we want to draw?

The answer, my friend, is a emphatic YES. And not only for each letter, uppercase and lowercase, but also for every number and symbol you want to show.

 
  • In fact this is the first system that computers have been using from the beginning to draw the characters on the screen.
 

To write the word PROMETEC, we have to define the corresponding letters:

byte P[] = { 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40 };
byte R[] = { 0x78, 0x44, 0x44, 0x78, 0x70, 0x58, 0x4C, 0x46 };
byte O[] = { 0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C };
byte M[] = { 0x66, 0x7E, 0x5A, 0x42, 0x42, 0x42, 0x42, 0x42 };
byte E[] = { 0x7C, 0x40, 0x40, 0x78, 0x78, 0x40, 0x40, 0x7C };
byte T[] = { 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 };
byte C[] = { 0x7c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7C };
byte G[] = { 0x38, 0x44, 0x40, 0x40, 0x40, 0x4E, 0x44, 0x38 };
byte dot[]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06 };
byte sp[]= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

Let’s see now how can we show one of these letters in the display. First, we will use the GetBit()function, from the previous chapter, to extract the information we want to show on the display.

bool GetBit( byte N, int pos)
   {                           // pos = 7 6 5 4 3 2 1 0
       int b = N >> pos ;      // Shift bits
       b = b & 1 ;             // Gets only the last bit
       return b ;
   }

Therefore, we will sweep the rows and columns, to position each dot, and we will use the GetBit() function to know whether we should turn it up or not. Let’s start by defining inside the setup() function the array for the letter P:

 byte P[] = { 0x78, 0x44, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40 };
 void setup()                                        
    {   
        for (int j=2; j<19; j++)
             pinMode(j, OUTPUT);
        Serial.begin(9600);
    }

And next we define the scaffolding of the function that sweeps the rows and columns, without worrying about the pin numbers:

void loop()
   {
       for (int row = 0; row <8 ; row++)
          {
              byte F = P[row];
              for (int col =7; col >= 0 ; col--)
                 {
                 }
              Serial.print(F, HEX);
              Serial.print(",  ");
          }
       Serial.println();
   }

The Serial.print() functions located in the middle are there to verify that the code works properly (you can never know). Let’s get now the bit for each row and column to draw it on the screen and make sure that it works properly:

void loop()
   {
       for (int row = 0; row <8 ; row++)
          {
              byte F = P[row] ;
              for (int col =7; col >= 0 ; col--)
                 {
                     bool b = GetBit(F, col);
                     Serial.print(b);
                     Serial.print(",");
                 }
              Serial.println();
          }
       Serial.println("----------------------");
   }

Detalle consoloa Arduino
We check again that it shows properly the values of each bit, once the value of each dot of the display has been extracted. If you half close your eyes, you can almost distinguish the letter P among the 1s and 0s. Now we must convert the row and column values to Arduino pins. Remember that we access the columns via the Arduino pins from 2 to 9, but the second column corresponds to our seventh column, as we previously defined in the GetBit() function. As this is not my first dance, let’s see how can we do this slowly. We want to convert column values, ranging from 7 to 0, to pin values, ranging from 2 to 9. What formula can we apply?. Come on! Think a little. Simply this: Pin = 9 – col, that’s all. Let’s check it!

Row 0 1 2 3 4 5 6 7
9 – 0 9 -1 9-2 9-3 9-4 9-5 9-6 9-7
Pin 9 8 7 6 5 4 3 2

It was not so bad, was it?. Let’s see now how can we convert the rows from 0 to 7 to pins from 10 to 17 … Do you dare now, right? Pin = row + 10. We do need another small function before writing the entire sketch, a function to turn off all LED dots to clear the display:

   void Clear()
   {
      for (int j=2; j<10; j++)       // Values for the column pins
           digitalWrite(j, LOW);     // All turned off
   }

The columns are active in HIGH, so we set all LOW. And rows are active in LOW, so we set all HIGH. This guarantees that all dots are turned off. And then we turn up whichever interest us. The sketch will be more or less like this:

void loop()            
   {
      Clear();
      for (int row = 0; row <8 ; row++)
         {
             digitalWrite( row + 10 , LOW) ;           // We set the row
             byte F = P[row] ;
 
             for (int col =7; col >= 0 ; col--)
               {
                  bool b = GetBit(F, col)  ;
                  if (b)
                      digitalWrite( 9 - col  ,HIGH);   // We set the column
                   else
                      digitalWrite( 9 - col  ,LOW);    // If it is 0, turn it off 
                }                                   
             digitalWrite( row + 10 , HIGH) ;          // Turn off the row before exit
         }
   }

You can check that the sketch paints a pretty P on the display.
p_letter

Well, we are doing it pretty well. Of course it would be nice, to choose the letter we want to draw. And that is what we will do in the next sketch. To do this, we will write another function, to which we will pass the character we want to draw and the row where it is located (and it will return the corresponding row):

 

Sketch 45.2
byte Select( char c, byte row)
   {
       if ( c == 'P')          return(P[row]) ;
       if ( c == 'R')          return(R[row]) ;
       if ( c == 'O')          return(O[row]);
       if ( c == 'M')          return(M[row]);
       if ( c == 'E')          return(E[row]);
       if ( c == 'T')          return(T[row]);
       if ( c == 'C')          return(C[row]);
       if ( c == 'N')          return(N[row]);
       if ( c == '.')          return(dot[row]);
       if ( c == ' ')          return(sp[row]);
   }

And we will modify our previous loop besides, to turn it into a function, to which we pass the character we want to show. Iinside this function we will call the select() function to read the information of the corresponding array.

void SetChar(char p)
   {
       Clear();
       for (int row = 0; row <8 ; row++)
          {
             digitalWrite( row + 10 , LOW) ;                 // We set the row 
             byte F = Select( p, row);
             for (int col =7; col >= 0 ; col--)
                {
                    digitalWrite(8-col, LOW);                // We set the column to LOW 
                    bool b = GetBit(F, col)  ;
                    if (b)                                   // We set the column
                          digitalWrite( 9 - col  ,HIGH); 
                    else
                          digitalWrite( 9 - col  ,LOW);      // If it is 0, turn off 
                }
             digitalWrite( fil + 10 , HIGH) ;                // Turn off the row before exit 
          }
   }

We only need to write the loop:

void loop()
   {
       String s = "PROMETEC.ORG  ";
       int l = s.length();                      // Calculates the length of the string "s" 
       for ( int n = 0; n< l; n++ )
          {
              long t = millis();
              char c = s[n];
              while ( millis()< t+ 400)
              SetChar(c);
          }
   }

All that it does is to take one by one, the letters of the String s and call Setchar() to show them. But there is an additional complication, not to get bored. We discussed in a previous chapter that when multiplexing segments, or in this case dots, any attempt to use a delay will end up in disaster (do not believe me, try it) because the image on the display depends on the speed at which dots are refreshed and the delay simply prevents it. When you need a delay, as now, and you can not use a delay, using a while loop is usually safe.

 
  • Notice that I have added a couple of spaces at the end of the string s. As I have defined the spaces as all dots turned off, this gives us an additional delay before the function starts again..
 

 

SUMMARY

 
    • We have seen how to represent graphical characters in a dot matrix and how to compactly code this information bit by bit
    • We have created a sketch that extracts this information, bit by bit, in order to represent a character on the display.
    • As programs become more complex, we learn how to split problems into smaller pieces that are easier to handle.
 

 

No Comments

Give a Reply