Tuesday, August 27, 2013

30. Multiplexing the 8 x 8 LED Array

The last post described a sketch that simply addressed a single LED, switched it on, switched it off, and then moved on to the next LED.  There is only one on at a time, even though when the routine speeds up enough, whole rows or whole columns appear to move and eventually the whole 64 LEDs appear to be glowing. 

A problem arises when we want to have more than one LED on at a time.  Let's look at the matrix again:


Take as an example, if LED (row4, column5) and LED (row5, column7) are to be lit at the same time, then Row 4 and Row 5 must be HIGH and Column 5 and Column 7 must be LOW.  

In order that no other LEDs are lit, all other rows must be no higher than all other columns.  However, if rows 4 and 5 are HIGH and columns 5 and 7 are LOW,  there are other LEDs which will be activated - in this case, LED (row4, column7) and LED (row5, column5).  

So this is where timing comes in (scanning, or multiplexing).  The required LEDs must be activated one at a time.  LED (row4, column5) and LED (row5, column7) must be activated alternately, meaning that each of them must be OFF for some of the time, while the other is ON.   If the switching is done fast enough, the eye-brain system of the observer will not notice that the LEDs are in fact blinking.

So the effect that we saw above, where more than one LED is flashing on and off very fast (about 1000 times per second), is used to give the impression that more than one LED is lit at the same time - ie that patterns are illuminated.

The sketch was borrowed from Michael Margolis' Arduino Cookbook 2nd Edition, and is also a simple routine, scanning rows and then columns, and lighting up the LEDs - except this time, the LEDs stay ON until the end of the cycle.

Here is the code:

1:  /*  
2:   * matrixMpx sketch by Michael Margolis in Arduino Cookbook 2nd Ed  
3:   * Sequence LEDs starting from first column and row until all LEDS are lit  
4:   * Multiplexing is used to control 64 LEDs with 16 pins  
5:   */  
6:    
7:  const int columnPins[] = { 6,11,10,3,17,4,8,9};  
8:  const int rowPins[]  = { 2,7,19,5,13,18,12,16};  
9:    
10:  int pixel    = 0;    // 0 to 63 LEDs in the matrix  
11:  int columnLevel = 0;    // pixel value converted into LED column  
12:  int rowLevel  = 0;    // pixel value converted into LED row  
13:    
14:  void setup() {  
15:   for (int i = 0; i < 8; i++)  
16:   {  
17:    pinMode(columnPins[i], OUTPUT); // make all the LED pins outputs  
18:    pinMode(rowPins[i], OUTPUT);  
19:   }  
20:  }  
21:    
22:  void loop() {  
23:   pixel = pixel + 1;  
24:   if(pixel > 63)  
25:     pixel = 0;  
26:    
27:   columnLevel = pixel / 8;           // map to the number of columns  
28:   rowLevel = pixel % 8;            // get the fractional value  
29:   for (int column = 0; column < 8; column++)  
30:   {  
31:    digitalWrite(columnPins[column], LOW);   // connect this column to Ground  
32:    for(int row = 0; row < 8; row++)  
33:    {  
34:     if (columnLevel > column)  
35:     {  
36:      digitalWrite(rowPins[row], HIGH); // connect all LEDs in row to +5 volts  
37:     }  
38:     else if (columnLevel == column && rowLevel >= row)  
39:     {  
40:       digitalWrite(rowPins[row], HIGH);  
41:     }  
42:     else  
43:     {  
44:      digitalWrite(columnPins[column], LOW); // turn off all LEDs in this row  
45:     }  
46:     delayMicroseconds(300);   // delay gives frame time of 20ms for 64 LEDs  
47:     digitalWrite(rowPins[row], LOW);     // turn off LED  
48:    }  
49:    
50:    digitalWrite(columnPins[column], HIGH);  // disconnect this column from GND  
51:   }  
52:  }  
53:       
54:      


Each 'pixel' is activated in turn, and in line 46, there is a 300 µs delay after switching ON, long enough for the eye-brain system to 'see' the LED illuminated.  However, the eye doesn't 'notice' that the LED has been switched OFF at line 47, yet it perceives all the LEDs which have been switched ON as still being ON.  Good old Persistence of Vision again!  Here's what it looks like to the camera:


More great music - eh??  Pretty much the same as the naked eye sees!  (Although if you look carefully, you will see that the camera has picked up a flickering effect which the naked eye doesn't see - why then does the eye see flickering on the video and not in real life?). 

Notice that the number of connection pins needed for the 8 x 8 matrix is 16 - the sum of the number of rows plus the number of columns.  Thanks to multiplexing, this is a lot less than needing 64 individual pins!

There is another technique, which I'll look at later, called Charlieplexing, which is even more economical on connection pins, and in the case of an 8 x 8 matrix, can reduce the number of pins needed to 12.  Let's save this for a future post.


No comments:

Post a Comment