Shift registers and LED's

I have been using Arduino Uno and two 74HC595 shift registers daisy chained to control 16 LED’s and now I would like to have independent control of 64 LED’s in an 8 x 8 matrix wired as per attached diagram 1. As I see it, from my limited knowledge, the shift register connected to the anodes via resistors and transistors would set the appropriate anode row HIGH and the second shift register connected to the cathodes would set the appropriate cathode column LOW. I understand the basic concept of coding for a single shift register to control eight LED’s in whatever order I want them to light or not, but this matrix is baffling me. I only really want to do this to further my understanding the procedure with a view to ultimately building an 8 x 8 x 8 LED cube controlled by Arduino Uno and 8 bit shift registers. If someone could give me a few clues in lay terms I would appreciate some help. Thanks for your time Pedro.

8 x 8 Matrix (part).doc (21.5 KB)

Have a read of this

Thanks for that Mike. I have seen your excellent electronic tutorials etc on your site and elsewhere online but to be honest this one is above my skill level. I “somewhat” understand current syncing and sourcing to reduce the current that is actually drawn from the Arduino but was just hoping for some “simple code” to drive the shift registers I mentioned so I might start to understand how they might be used to control a matrix. However I will persist in trying to understand more of what you explain in this tutorial and thanks again for your response, Pedro.

Try this Pedro. Not debugged, should be pretty close.
Some might suggest burying stuff in functions, I say skip that and just let it run fast!

// code to read data from an 8 byte array and display on 8x8 LED matrix with shift registers and current limit resistors driving anodes, 
// and shift register with high current drivers sinking common cathodes.
// SPI commands will be used to send the data out

// sequence: every xx milliseconds, turn off all cathodes
// set up anodes from data stored in an array
// turn on next cathode
// while time is passing for the next set of anodes, do other stuff
// repeat

#include <SPI.h> // bring in SPI library

byte SSanodes = 9; // output latch for anodes shift register.  Can be any pin except 10,11,12,13.
byte SScathodes = 10; // output latch for cathodes shift register.  Pin D10 needs to be an output for SPI.
byte dataArray[]= {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};  // load up some initial data
// dataArray[0] = B00000001
// dataArray[1] = B00000010
// dataArray[2] = B00000100
// dataArray[3] = B00001000
// dataArray[4] = B00010000
// dataArray[5] = B00100000
// dataArray[6] = B01000000
// dataArray[7] = B10000000

byte cathodePins[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};  // used to turn on 1 cathode at a time

unsigned long timeNow = 0;  // capture time
unsigned long previousTime = 0; // store previous time
unsigned long elapsedTime = 5; // time that each column will be on

byte anodeColumn = 0;  // keep track of column being driven

void setup(){
pinMode (SSanodes, OUTPUT);
pinMode (SScathodes, OUTPUT);

SPI.begin();  // commits 11,12,13 for hardware SPI transfer. Make sure shift registers have 0.1uF/100nF on their VCC pins to ground.

void loop(){

timeNow = millis(); // capture the current 'time'
if ((timeNow - previousTime)>= elapsedTime){  // display refresh time?
previousTime = previousTime + elapsedTime; //setup for next pass

// keep track of which column is being written
anodeColumn = anodeColumn+1;
if (anodeColumn == 8){anodeColumn = 0;}  // reset after going 0,1,2,3,4,5,6,7 >> 0

// turn off current cathode
digitalWrite (SScathodes, LOW);
SPI.transfer(0); // 0 = all cathode off >> assumes HC595 driving base of NPN transistor or ULN2803
digitalWrite (SScathodes, HIGH);

// shift out next set of anodes
digitalWrite (SSanodes, LOW);
SPI.transfer(dataArray[anodeColumn]); // read data from the array and send it out
digitalWrite (SSanodes, HIGH);

// turn the next cathode on
digitalWrite (SScathodes, LOW);
SPI.transfer(cathodePins[anodeColumn]); // 0 = all cathode off >> assumes HC595 driving base of NPN transistor or ULN2803
digitalWrite (SScathodes, HIGH);

} // end of time check

// make sure that all compiles & runs okay. If too flickery, decrease elapsedTime. Maybe even go to micros() instead of millis();

// next, add your code to read buttons, receive serial data, whatever your method for making updates to dataArray[x]
// for example, this should move the On LED in each row across the screen every 1/2 second
/*  add variable definitions as above
// timeNow already captured at the top of void loop
if ( (timeNow - previousShiftTime)>= elapsedShiftTime){
previousShiftTime = previousShiftTime + elapsedShiftTime;
tempArray = arrayData[0];  // store column 0
arrayData[0] = arrayData[1]; // column 0 becomes column 1
arrayData[1] = arrayData[2]; // 1 becomes 2
arrayData[2] = arrayData[3];
arrayData[3] = arrayData[4];
arrayData[4] = arrayData[5];
arrayData[5] = arrayData[6];
arrayData[6] = arrayData[7];
arrayData[7] = tempArray;  // finally 7 becomes what 0 was.
// display will show the new data at the next display update interval

} // end void loop

Thanks for that Crossroads, I will build that matrix and try your code out. I just wanted to make sure that using shift registers was a viable option before actually building the matrix. Thanks again Pedro

Wow, tried to compile that, only 2 errors!

Needed to add these to the top of the sketch:

#include <SPI.h>
byte anodeColumn = 0;

Revised post above to include them.

Hey you're working on this harder than I am... your making me look bad. If I draw up how I think the circuit should go, would you mind perusing it and pointing out the inevitable mistakes I know that I am going to make. Thanks Pedro.


What, you mean this?
Picture it rotated 90 degrees counter-clockwise so the anodes are driven from the left and the cathodes from the bottom.

Good God man, you've done it... what do you walk around carrying 8 x 8 matrix circuit diagrams in your back pocket? XD

No, it had been drawn up already for an earlier discussion. Is there a way to see the date on that file? Oct 2011 8)

As my knowledge of electronics is rudimentary, I am trying to understand the basic power flow in this matrix. As I see it the Arduino digital signal goes to the input of the anode shift register which applies current to the selected anode row of the matrix. The cathode shift register which is daisy chained to the anode shift register sends it’s output to the input of the ULN2803. The output of the ULN2803 goes to the cathode columns of the matrix.
Therefore when the selected input of the ULN2803 receives current from the corresponding output of the cathode shift register, ground is applied to the corresponding output of the cathode shift register, effectively grounding the relevant matrix cathode column and lighting the LED. I apologise for my verbose, and more than likely technically inept explanation and have attached a basic flow chart which hopefully makes sense. Is this anything close to how it might operate and be constructed ? Thanks for your time, again… Pedro.

8 X 8 Matrix flow chart.pdf (5.59 KB)

You are basically correct.

I did not daisy chain them in the code, I made the anodes seperately writeable from the cathodes.

8 bits are shifted into the cathode shift register, turning off any high outputs, which turns off any UN2803 outputs.
8 bits are shifted into the Anode shift register, can be high or low.
8 bits are shifted into cathode shift register, only one will be a 1. The ULN2803 output for that 1 goes Low, any LEDs with a high anode turned on.

By wiring SCK & MOSI to both shift registers in parallel, both shift register input stages are loaded with the same data every time. Only the shift register that gets the seperate Register Clock (SSanode or SScathode) has the data moved to the output stage to show up at the LED matrix.

Compare that to daisy chaining them, where 2 bytes must be shifted out every time, even tho the anode outputs only change 1 of those times:
cathodes off + no anode change
cathodes off + new anodes
cathode on + no anode change

vs just 1 byte
cathodes off
new anodes
cathode on

Having the cathode off before changing the anode prevents any ghosting as the display is updated.
The digitalWrite for the Register Clock will be slow part of this operation, that can be changed to direct port manipulation later to really speed it up.
One thing at a time tho …

8_X_8_Matrix_flow_chart[1].docx (12.3 KB)

I am endeavouring to draw up the matrix circuit based on my limited use of 74HC595 shift registers and Crossroads invaluable help. There seems to be a few different pinouts for the components but the ones I will be using worked o.k. when I used them to drive eight LED’s using them as in attached diagram 1.

Crossroads from what you indicated in your code and flow chart, I thought that;

Pin 9 Arduino might go to pin 12 of anodes shift register
Pin 10 Arduino might go to pin 12 of cathodes shift register

It seems that pin 8 of my shift registers are VCC ? where you indicate 0.1uf – 100nf capacitors ?

I see from your flowchart that Arduino pins 11, and 13 go, in parallel to the SCK and RCK pins of the two shift registers but there seem to be a multitude of names for these pins and I am uncertain as to what pin is what on the shift registers that I am using.

Also in the eight LED matrix circuit attached, pin 13 (OE) went to ground – what about in this 8 x 8 matrix ?

I apologise for being so vague, but as stated I am a rank but enthusiastic amatuer here. (It’s been a long day…)

I have included the circuit diagram 2 of what I have drawn up so far and would appreciate some further guidance if possible.

Thanks Pedro.

p.s – I just realise that I wired up the outputs of the cathode shift register to the inputs of the ULN2803 in the reverse order

Diagram 2.bmp (958 KB)

For some reason Diagram 1 did not hurtle through cyber-space too… so here it comes 8)

Diagram 1.bmp (1.12 MB)

I have been “goggling my heart out” 8), and am I right in suggesting that;
SCK is shift register clock input which is pin 11 SH CP of the shift register
RCK is storage register clock input which is pin 12 ST CP of the shift register
Serial data is pin 14 DS of the shift register
So I connect;
Arduino pin 9 to anode shift register pin 12
Arduino pin 10 to cathode shift register pin 12
Arduino pin 13 to pin 11 on both anode and cathode shift registers
Arduino pin 11 to pin 14 on both anode and cathode shift registers

If this is all correct I am still wondering about the necessity of the ground to shift register pins 13 OE that I used in the single shift register driving eight LED’s circuit (are they required in this circuit?) and if those capacitors are in the right place on shift register pin 8 (if this is in fact pin VCC)
Also does the rest of the circuit appear to be o.k. apart from my homemade shift register and ULN2803 symbols.

MR must be held High, making it low clears the outputs.
OE must be held Low, making it high disables the output drivers.
High Power pin is either called Vcc or Vdd. Connects to 5V or 3.3V typically.
Low Power pin is called Vss. Connects to Ground typically.

Thanks again for that Crossroads. I have got some ULN2803's coming on "the slow boat from China" so when they arrive I will put it all together and see how I go. Pedro.

I finally received the ULN2803 arrays to complete the 8 x 8 matrix and after connecting it all up have eventually got a diagonal row of LED's lighting from left to right, top to bottom. Not knowing anything about the coding in the test array ({0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; I do not really know where to go from here… (now there's something new hey ) :D Does it look like it is operating as it should and if so how do I "move forward" as they say in the classics. Thanks again Pedro.

Good news! The array would indeed make a diagonal line.

What is it you wanted to display? You could have static 'pictures' defined, and every so often switch to a new one. Maybe based on time, maybe when a button is pushed, maybe when a serial message was received. You could have the display slowly scroll left or right, or up & down. Put what else you want displayed in a larger array and read that data out and write it to the display array. Or make up what is being displayed on the fly.

Thanks for the good news Crossroads. I am glad that my perseverance with sorting out the wiring paid off, I love it when a plan comes together. I suppose that I want to try and understand how to use your code to perform simple displays so that I can start to understand how the arrays control the matrix. For example with the 3 x 3 x 3 cube that you helped me with, I found some PatternTable code that I found useful and after much head scratching and rewiring, worked out which part of the array was controlling each LED. i.e. - in this array {B100, B000, B000, B000, B000, B000, B000, B000, B000} ; on my cube this would turn on the first LED on the top level and I also deduced that the first nine numeric's controlled the nine LED's on the top level, the 10th to 18th numeric's the center level LED's etc. and obviously a one was on and zero off. I know that it's not rocket science, but to me it showed me how to use the code to control the cube in a much simpler way that turning everything on and off one by one, and that using arrays is the way to go. I therefore would like to develop a similar understanding of this matrix code so that I can start to control simple things like individual control of each LED, scrolling lights etc and eventually static and scrolling symbols and text. I don't even recognize the array that you have used here; byte dataArray[]= {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; Thanks again for your help in trying to educate me Pedro.