Feed on
Posts

Fun with 8×8 LED Matrix

I’ve finally got around to wiring up my 8×8 LED Matrix and now it’s time for some fun with it. Though out playing with this I’ve learnt about shift registers and how we can use them along with a transistor array chip.

First things first, have a read and look through the Arduino’s ShiftOut guide as they are very well put together (keep re-reading it if it doesn’t make sense): http://www.arduino.cc/en/Tutorial/ShiftOut

To summarise the guide:

• A shift register allows you to have 8 outputs while only using 3 pins on the Arduino
• You send a byte to the shift register which has 8 bits (e.g. 10010000)
• You can combine shift registers so instead of having only 8 outputs you can have 16 when using 2, 24 when using 3, and so on
• When combining shift registers, instead of sending out the 8 bits to the first register and 8 to the second register it’s actually reversed, so the first 8 bits you send are actually for the second register and the next 8 bits go to the first register

It seems like the Arduino ShiftOut code examples code was different almost in each example so which way is the easiest to doing this? I found the example that used bitWrite to be the easiest to use as below.

```byte bitsToSend = 0;
digitalWrite(latchPin, LOW);
bitWrite(bitsToSend, 0, HIGH);
bitWrite(bitsToSend, 3, HIGH);
shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);
digitalWrite(latchPin, HIGH);```

This is an example to use with only 1 shift register. Firstly you assign the variable bitsToSend as a byte which is 8 bits (e.g. 00000000), then you put the latchPin to low to tell the shift register that you will be sending the new state of the outputs. Now is where the bitWrite function comes in, bitWrite modifies the bitsToSend variable and turns on the bit number we specify as 1. So in our example, the 3rd line in our program would now change bitsToSend from 00000000 to 00000001.

The next line would change it from 00000001 to 00001001, so you see it has the number 3 in our bitWrite which basically says count (right to left) to 4 (because we start at 0) and assign a 1 to the number you reach.

Now that we have our byte to send, we use the shiftOut function to send the byte to the shift register (which sends each bit one by one) and then we turn latchPin back on to say we are done and that the shift register can now enable the outputs we’ve specified which are outputs 0 and 3, so the LEDs assigned to those outputs would light up as per the layout below (it’s been simplified so it’s easier to understand)

So by now you should have an understanding of how shift registers are used, we’ll jump into using them to controller a LED Matrix of 64 LEDs (8×8).

Parts used

• 2 x 74HC595 Serial Shift Register
• 1 x ULN2803A Darlington Array (of Transistors)
• 8 x 220 Ohm 1/4W Resistor

Schematic

So lets read our schematic, with our LED Matrix we have 8 rows (ROW1, etc) and 8 columns (RED1, etc), row 0 and column 0 for us will start at the top left. The first shift register controls the rows and the second shift register controls the darlington array which in turn controls the columns. We know how the rows work with the single shift register, so how does the darlington array work with the shift register?

We know how transistors work from our previous posts, the darlington array has Inputs, Outputs and the ground. All we need to do is connect the outputs from the shift register to the darlington array, connect the columns to the darlington array outputs, then the ground and you’re done. Simple hey?

How it works

We tell the Arduino to send out 2 bytes (00000001 00001000) to the first shift register. The first byte is passed on to the second shift register (00000001) which controls the columns, this byte gets processed as turn on output 0. Output 0 is enabled which switches on the first transistor in the ULN chip, this then allows the column 0 of the LED matrix to be activated and allow current to flow into it.

Now we go back to our first shift register and that has received the second byte (00001000) which controls the rows and says turn on output 3 which turns on the LED as below.

And that’s it! Now you might be wondering how can we turn on say the led on row 3, column 0 and then row 6, column 1? It can be achieved by turning on each column really fast; by fast I mean every 2 milliseconds (ms). So each 2ms, we turn on the next column and the row outputs associated with it.

Software

Well you should have already picked this up at the start but here is the complete source code for turning on row 0 and 3 in column 0.

```//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
//Pin connected to DS of 74HC595
int dataPin = 11;

void setup() {
//set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}

void loop() {
byte rowBitsToSend = 0;
byte columnBitsToSend = 0;
digitalWrite(latchPin, LOW);
bitWrite(columnBitsToSend, 0, HIGH); // Gives us 000000001
shiftOut(dataPin, clockPin, MSBFIRST, columnBitsToSend); // Send the byte to the shift register which passes it to the second shift register
bitWrite(rowBitsToSend, 0, HIGH); // Gives us 00000001
bitWrite(rowBitsToSend, 3, HIGH); // Adds on to the previous modified bits to give us 00001001
shiftOut(dataPin, clockPin, MSBFIRST, rowBitsToSend); // Send the byte to the shift register
digitalWrite(latchPin, HIGH); // Tell the shift register we are done sending data so it can enable the outputs
delay(2); // Not really necessary in this example but it will be for lighting up multiple columns
}
```

Time for some fun

View the video below for these.

5. How lighting up the LED Matrix works

Edit: I’ve been advised that you don’t actually need a Darlington array for this, you could use the second shift register to become the ground. Shifting a 1 would disable the ground and shifting a 0 would enable ground.

73 Responses to “Fun with 8×8 LED Matrix”

1. sergey says:

hello! can you explain how to scroll a text string more than two letters! Thank you! Pleas post it in your site. or modify sketch that scrolls text

Hi, In example 4: Display scrolling text you can make these changes.

Before
if (counter % 25 == 0) {

if (movement == 16) {
int x;
int y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
LEDs[x][y+8] = letterI[x][y];
}
}
}

Find
if (movement >= 16) {

Change to
if (movement >= 24) {

Now it will say HII instead of just HI.

To add different letters you will need to make a new array like:
int letterC[8][8] = {
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 1, 1, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
};

It might be easier to view this post: http://www.insidegadgets.com/2010/12/10/led-matrix-road-runner/ and then just use the FastLCD program to write the text on.

• sergey says:

Hello again!
I have used your suggestions! it works! thanks! now i have several questions.
1.What type of matrix do you use common anode or cathode, I used c/c and had to change connections uln to rows 595 to columns/
2. how to change speed of scrolling?

Hiya, good to hear!

1. I didn’t get to choose, I just ordered one and got a common cathode one. (Now that I look at my schematic in this post it looks like I drew it for c/a)

2. If you are using the code in this post, you change the number 25 in the line “if (counter % 25 == 0) {“. For faster scrolling decrease the number. If you are using the FastLCD post, you just change the variable “int scrollSpeed = 35;”.

• sergey says:

Hi! http://ukrduino.blogspot.com/2011/02/8×8-led-matrix.html – post about my experiments with matrix.
I have hand made RTC-EEPROM Shield, and going to display time and then temperature on this matrix!

Cool :D. Thank you for the link back here 😉

• sergey says:

Hi! Again!
I have written sketch for matrix, but does not works… Can you help me?
look at it:

2. sergey says:

#include
#include
#include

// buffer for time display;
char timeBuffer[] = “1245”;

//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
//Pin connected to DS of 74HC595
int dataPin = 11;

int counter = 0;
int movement = 0;
// digits of clock to scroll
int h1[8][8];
int h2[8][8];
int m1[8][8];
int m2[8][8];

int LEDs[8][17] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

int letter0[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letter1[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 1
{ 0, 0, 0, 0, 1, 0, 0, 0 } ,// ____X___
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 1, 0, 1, 0, 0, 0 } ,// __X_X___
{ 0, 0, 0, 0, 1, 0, 0, 0 } ,// ____X___
{ 0, 0, 0, 0, 1, 0, 0, 0 } ,// ____X___
{ 0, 0, 0, 1, 1, 1, 0, 0 } ,// ___XXX__
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letter2[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 2
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 0, 0, 1, 0, 0, 0 } ,// ____X___
{ 0, 0, 0, 1, 0, 0, 0, 0 } ,// ___X____
{ 0, 0, 1, 0, 0, 0, 0, 0 } ,// __X_____
{ 0, 0, 1, 1, 1, 1, 0, 0 } ,// __XXXX__
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letter3[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 3
{ 0, 0, 1, 1, 1, 1, 0, 0 } ,// __XXXX__
{ 0, 0, 0, 0, 0, 1, 0, 0 } ,// _____X__
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 0, 0, 1, 0, 0 } ,// _____X__
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letter4[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 4
{ 0, 0, 0, 0, 0, 1, 0, 0 } ,// _____X__
{ 0, 0, 0, 0, 1, 1, 0, 0 } ,// ____XX__
{ 0, 0, 0, 1, 0, 1, 0, 0 } ,// ___X_X__
{ 0, 0, 1, 1, 1, 1, 0, 0 } ,// __XXXX__
{ 0, 0, 0, 0, 0, 1, 0, 0 } ,// _____X__
{ 0, 0, 0, 0, 0, 1, 0, 0 } ,// _____X__
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letter5[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 5
{ 0, 0, 1, 1, 1, 1, 0, 0 } ,// __XXXX__
{ 0, 0, 1, 0, 0, 0, 0, 0 } ,// __X_____
{ 0, 0, 1, 1, 1, 0, 0, 0 } ,// __XXX___
{ 0, 0, 0, 0, 0, 1, 0, 0 } ,// _____X__
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letter6[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 6
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 1, 0, 0, 0, 0, 0 } ,// __X_____
{ 0, 0, 1, 1, 1, 0, 0, 0 } ,// __XXX___
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letter7[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 7
{ 0, 0, 1, 1, 1, 1, 0, 0 } ,// __XXXX__
{ 0, 0, 0, 0, 0, 1, 0, 0 } ,// _____X__
{ 0, 0, 0, 0, 1, 0, 0, 0 } ,// ____X__
{ 0, 0, 0, 1, 0, 0, 0, 0 } ,// ___X___
{ 0, 0, 0, 1, 0, 0, 0, 0 } ,// ___X____
{ 0, 0, 0, 1, 0, 0, 0, 0 } ,// ___X____
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letter8[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 8
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letter9[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 9
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 0, 1, 1, 1, 0, 0 } ,// ___XXX__
{ 0, 0, 0, 0, 0, 1, 0, 0 } ,// _____X__
{ 0, 0, 1, 0, 0, 1, 0, 0 } ,// __X__X__
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};
int letterh[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________ 9
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 1, 1, 0, 0, 0 } ,// ___XX___
{ 0, 0, 0, 0, 0, 0, 0, 0 } ,// ________
};

void setup() {
//set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
Serial.begin(57600);
Wire.begin();

}

void loop() {
updateTimeBuffer();

if (movement == 0) {
int x;
int y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
LEDs[x][y+8] = letter8[x][y];
}
}
}
if (movement == 8) {
int x;
int y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
LEDs[x][y+8] = h2[x][y];
}
}
}
if (movement == 16) {
int x;
int y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
LEDs[x][y+8] = letterh[x][y];
}
}
}
if (movement == 24) {
int x;
int y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
LEDs[x][y+8] = m1[x][y];
}
}
}
if (movement == 32) {
int x;
int y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
LEDs[x][y+8] = m2[x][y];
}
}
}
if (counter % 10 == 0) {
movement++;
int x;
int y;
for (x = 0; x < 8; x++) {
for (y = 0; y = 40) {
counter = 0;
movement = 0;
}

lightLED();
counter++;
}

void lightLED() {
byte columnbitsToSend = 0;
byte rowbitsToSend = 0;

int x = 0;
int y = 0;
for (x = 0; x < 8; x++) {
columnbitsToSend = 0;
rowbitsToSend = 0;

for (y = 0; y < 8; y ++) {
if (LEDs[x][y] == 1) {
bitWrite(rowbitsToSend, y, HIGH);
}
}

digitalWrite(latchPin, LOW);
bitWrite(columnbitsToSend, x, HIGH);
shiftOut(dataPin, clockPin, MSBFIRST, columnbitsToSend);
shiftOut(dataPin, clockPin, MSBFIRST, rowbitsToSend);
digitalWrite(latchPin, HIGH);
delay(2);
}
}
void updateTimeBuffer()
{ int rtc[7];
RTC.get(rtc, true);
int second = rtc[0];
int minute = rtc[1];
int hour = rtc[2];
int day = rtc[4];
int month = rtc[5];
int year = rtc[6];
// build the string containing formatted time; – this works good
timeBuffer[0] = (hour < 10) ? ' ' : ('0' + hour/10);
timeBuffer[1] = '0' + hour%10;
timeBuffer[2] = '0' + minute/10;
timeBuffer[3] = '0' + minute%10;
// i think problem is here…..
if (timeBuffer[0]==0){h1[8][8]=letter0[8][8];}
if (timeBuffer[0]==1){h1[8][8]=letter1[8][8];}
if (timeBuffer[0]==2){h1[8][8]=letter2[8][8];}
if (timeBuffer[1]==0){h2[8][8]=letter0[8][8];}
if (timeBuffer[1]==1){h2[8][8]=letter1[8][8];}
if (timeBuffer[1]==2){h2[8][8]=letter2[8][8];}
if (timeBuffer[1]==3){h2[8][8]=letter3[8][8];}
if (timeBuffer[1]==4){h2[8][8]=letter4[8][8];}
if (timeBuffer[1]==5){h2[8][8]=letter5[8][8];}
if (timeBuffer[1]==6){h2[8][8]=letter6[8][8];}
if (timeBuffer[1]==7){h2[8][8]=letter7[8][8];}
if (timeBuffer[1]==8){h2[8][8]=letter8[8][8];}
if (timeBuffer[1]==9){h2[8][8]=letter9[8][8];}
if (timeBuffer[2]==0){m1[8][8]=letter0[8][8];}
if (timeBuffer[2]==1){m1[8][8]=letter1[8][8];}
if (timeBuffer[2]==2){m1[8][8]=letter2[8][8];}
if (timeBuffer[2]==3){m1[8][8]=letter3[8][8];}
if (timeBuffer[2]==4){m1[8][8]=letter4[8][8];}
if (timeBuffer[2]==5){m1[8][8]=letter5[8][8];}
if (timeBuffer[3]==0){m2[8][8]=letter0[8][8];}
if (timeBuffer[3]==1){m2[8][8]=letter1[8][8];}
if (timeBuffer[3]==2){m2[8][8]=letter2[8][8];}
if (timeBuffer[3]==3){m2[8][8]=letter3[8][8];}
if (timeBuffer[3]==4){m2[8][8]=letter4[8][8];}
if (timeBuffer[3]==5){m2[8][8]=letter5[8][8];}
if (timeBuffer[3]==6){m2[8][8]=letter6[8][8];}
if (timeBuffer[3]==7){m2[8][8]=letter7[8][8];}
if (timeBuffer[3]==8){m2[8][8]=letter8[8][8];}
if (timeBuffer[3]==9){m2[8][8]=letter9[8][8];}
}

• sergey says:

OH!!! I have fix code!
if (timeBuffer[0]==0){h1[8][8]=letter0[8][8];}
i used
if (h22 == 56) {
int x;
int y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
h2[x][y] = letter7[x][y];
but i dont know how to convert char timeBuffer[] in dec …

Hello what is code

Hi, for long code pastes you should use http://pastie.org/ so it’s easier to see your code. Example: http://pastie.org/1611545

In your if (counter % 10 == 0) { part, it seems like something is missing. It has for (y = 0; y = 40) and counter = 0; etc in the wrong place so your text might not scroll.

To convert char timeBuffer into decimal, you would minus ‘0’ from each individual character. I assume that timeBuffer is “1256” for 12:56pm for my example below.
char timeBuffer[] = “1256”;
int timeDec[4];
for (int x = 0; x < 4; x++) {
timeDec[x] = timeBuffer[x] – '0';
}
// timeDec[0] is now 1
// timeDec[1] is now 2
// timeDec[2] is now 5
// timeDec[3] is now 6

4. sergey says:

Hello!
i`ve fixed more mistakes and pasted code http://pastie.org/1612733
but it work only to line 354 ???
can you look at it?

Try to disable serial and see if it fixes it.

Perhaps you might be using too much SRAM, try commenting out int m2[8][8]; and then move the commenting out from line 367 to 376 and see what happens?

You have probably noticed that the time keeps on printing a lot of times a second on serial? Lets try to move this code:
updateTimeBuffer();
makeTimeSprites ();

to the setup() and after (movement >= 40). If we do this, the time will be updated at the start of the program and after the last minute has been shown.

E.g:
void setup() {
….
Serial.begin(57600);
Wire.begin();
updateTimeBuffer();
makeTimeSprites ();
}

and

if (movement >= 40) {
counter = 0;
movement = 0;
updateTimeBuffer();
makeTimeSprites ();
}

The Arduino with ATmega328 has 2K SRAM.

I have just checked the SRAM used when I compile it:
avr-size.exe pastie_1612733_pde.cpp.elf
text data bss dec hex filename
6626 926 1154 8706 2202 pastie_1612733_pde.cpp.elf

SRAM used = data 926 + bss 1154 = 2080 bytes. So you are already over the limit and funny things can happen.

Try this to reduce the SRAM size, rename all of the arrays:
int h1[8][8]; … etc
int letter0[8][8] … etc

to

byte h1[8][8]; … etc
byte letter0[8][8] … etc

Now instead of using 2 bytes for each value, we are just using 1 byte because we don’t need more than 255 values.

avr-size.exe pastie_1612733_pde.cpp.elf
text data bss dec hex filename
6520 478 762 7760 1e50 pastie_1612733_pde.cpp.elf

Now it’s been reduced!

7. sergey says:

Thank you for HELP!!!
Now its finally works. Look at my video!
http://ukrduino.blogspot.com/2011/03/arduino-scrolling-time-from-rtc-ds1307.html
The next idea is to add a “screen saver” – Random object moving around LED matrix, and showing time and temp every 30 sec. So, I think about adding one more matrix besides, and may be changing to dual R/g ones. (but i have only com/anode RG – will they work??? with the same schematic?).
Thank you again!!!

8. Alex says:

No problem, good to see it works 🙂

Yes the schematic will be different, here is a quick picture on how it would look with com/anode: http://img143.imageshack.us/img143/6048/shiftcommon.png

You would need to remove the ULN2803A chip because it only has NPN transistors, you would ideally need one with PNP transistors but in the example above we have just gone without a ULN device, the shift register should be ok to handle it as long as each LED is only getting about 2-3mA each.

Connect the resistors to Green shift and Red shift.

The code would need to change:
– Add extra shiftOut in lightLEDs (one for Green LEDs and one for Red LEDs)
– Change green shift and red shift “ShiftOut” to be the inverse because you are using these shift registers to be ground for the LEDs. Shifting 0 to pin 1 would make pin 1 grounded. So the default state for all pins of the 2 R/G shift registers would need to be 1. (This means that they are off. Shift 1 for off and 0 for on, i.e inverse)

It would be much easier to get a common cathode LED Matrix, then all you need to do is add 1 shift register and just add extra shiftOut in lightLEDs and that’s all.

Edit: So for the common anode what you do is hook up the first shift register to the anodes, the second shift to the red cathodes and the third to the green cathodes. Now what you do is to switch on a Red LED is shift out “1” on a pin of first shift register and then a “0” on a pin of the second shift register.

Hope it makes sense, if not let me know and I’ll try explain a bit more.

9. sergey says:

Hi! Alex!
I have one more :)) question for you…
i have combined DS 1307, 18b20 and matrix …
time shows good! but temp…. not…. first digit of temp don’t changes
look at my post http://ukrduino.blogspot.com/2011/03/8×8-led-matrix-rtc-ds1307-18b20.htm and at sketch http://pastie.org/1644938
i think problem is in gettemp ()….

• Alex says:

Hey Sergey,

It looks like it should work but as your picture on your website shows, no values are being printed which doesn’t seem right.

I think it might be because of: tempDec[0] = (int (temp))/10;

Can you try: tempDec[0] = (int) temp/10;
Also try: Serial.print(tempDec[0], DEC);
How about just printing temp out to make sure it exists: Serial.println(temp);
Another thing to try: temp= (int) sensors.getTempCByIndex(0);

Hope that helps.

10. sergey says:

Hello! Alex!
i have fixed code changing
byte tempDec[2]; to int tempDec[2]; and deleting all that showed time.
i dont know why… but it works… (Nauris (LATVIА) advised me in my blog).
but the in whole scetch (with showing time) temp showing still not works 🙁 )
may be lack of SRAM again? show me where i can see it???

other question… if i change such block
if (tempDec[0] == 3) {
byte x;
byte y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
t1[x][y] = letter3[x][y];
to void…

void selectletter(x1, x2, x3, x4, x5)
{
if (x1[x2] == x3) {
byte x;
byte y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
x4[x][y] = x5[x][y];

}

11. Alex says:

Hey again,

Changing to int tempDec[2] I can only think that each value had to be more than 255 which is strange…

To check the SRAM follow this guide: http://www.designer2k2.at/index.php?option=com_content&view=article&id=49:arduino-ram-overflow&catid=13:arduino&Itemid=40 – you add BSS and DATA to get the SRAM

selectletter could work but needs a bit more work done to it.

12. sergey says:

super BUG, you have to see it!!!
second digit of minutes changes first digit of temp!
Sketch http://pastie.org/1667298
Serial log http://pastie.org/1667331

• Alex says:

Yeah that’s pretty weird!

Firstly to stop the blinking change follow the below. There was a bug in my code that keeps running (movement == x) for 5 times, thank you for the youtube video showing it. Please follow the changes here: http://pastie.org/1669876

I think more debugging is needed:
– Try to comment out updateTimeBuffer(); and see what happens?
– Add Serial.print(” – “); Serial.println(tempDec[0], DEC); to the other movements to find the exact movement that causes it to lose the value

hi mr, I have a 8X32 matrix led module, but shift and uln2308 as a line, and shift the other one as a column, how can I modify your code to work on my modules, I was new in the microcontroller, so I ask your help.

• Alex says:

You would need to change LEDs[8][8] to suit your matrix.

And add more of these to suit depending on how your matrix works:
shiftOut(dataPin, clockPin, MSBFIRST, columnbitsToSend);
or
shiftOut(dataPin, clockPin, MSBFIRST, rowbitsToSend);

And modify one of these to < 32: for (x = 0; x < 8; x++) { or or (y = 0; y < 8; y ++) {

thank you,i will try first.

hi again,do you have email?I want to send a 8X32 matrix led scheme, sorry if I bother you.

14. Gabor says:

Hi there, a very good tutorial, Congrats on it. I have a question, I built my LED matrix out of ordinary 5mm LED’s. So my question (actually not a question, I would need to be confirmed by you) is that in the schematic the Darlington array supply’s the current for the columns of the LED matrix, so in this case the LED’s Anode pins. Meaning that your Led Matrix has a common cathode setup for the rows? Also could you recommend a software where I could simulate my setup, before starting it up for real? I can’t seem to find a good software.

Thanks

• Alex says:

Hi Gabor,

In my example, the first 74HC595 is controlling the VCC and the darlington array is controlling the grounding of the LEDs. It is a common cathode but the darlington array is sinking the current whilst the first 74HC595 sources the current. The ULN2803 can only sink current, it can’t source current.

Regarding the software simulation – I haven’t been able to find a good / easy one to use.

• Gabor says:

Thank you Alex, I just wanted to understand how it works. I don’t really like working with parts I don’t understand how they work / what they do. And the data sheet’s were to technical. It was an eyeopener. Thanks again. 🙂

15. Gabor says:

Dear Alex,

I have one more question, would your setup work
if i would use only the darlington array to sink the curent. Meaning without the shiftregisters. I don`t understand the use of those. And in this case can i conect the darlingtons left side pins directly to the ardiuno?

• Alex says:

Hi Gabor,

It can work but it depends how much current you are sourcing from the Arduino, the Arduino (ATmega328) has a maximum of 40mA per pin and a total maximum of 200mA. The ULN2803 darlington array can be connected up to the Arduino directly as each pin would only take 1.8mA at 5V.

The shift registers are there to take the current load off the Arduino and to simply things so we only need 3 wires. The first shift register supplies the current to the LEDs you want to turn on whilst the darlington array sinks that current on the row you want that LED to light on.

• Gabor says:

Thanks, enlightening as always. 🙂

16. David says:

Hi Alex,

I have a matrix of 5 rows and 9 columns and I tried to make it work with your example of display text using two 74hc595 without the darlington. The problem is that anything happens, just turn on 4 rows and no more. Please can you help?

• Alex says:

Hi David,
If you are using just 2x 74hc595, you need to make sure to modify the code so you are inverting the 74hc595 that should have been on the darlington array (so instead of being 1 to turn on it would be 0).
A way to test it out would be to connect 1 column to ground or VCC (depending on if your matrix is common anode or cathode) and leave the rows on the 74hc595 so you should see the different rows light up on the single column you have to GND or VCC.

• David says:

hi alex,

I test it connecting 1 column to gnd and the rows to positive in the first shift register using this code:
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;

int counter = 0;
int LEDs[5][9] = {
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0}
};

{0,0,0,0,1,1,1,0,0},
{0,0,0,1,1,1,1,0,0},
{0,0,1,1,0,1,1,0,0},
{0,0,1,1,1,1,0,0,0},
{0,0,1,1,1,0,0,0,0}
};

int ojoderecha[5][9] = {
{0,0,0,1,1,1,0,0,0},
{0,0,1,1,1,1,0,0,0},
{0,1,1,0,1,1,0,0,0},
{0,1,1,1,1,0,0,0,0},
{0,1,1,1,0,0,0,0,0}
};

void setup()
{
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}

void loop()
{
if (counter 50) {
lightLED(ojoderecha);
}
if (counter > 100) {
counter = 0;
}
counter++;
}

void lightLED(int tempLED[5][9]) {
byte columnbitsToSend = 0;
byte rowbitsToSend = 0;

int x = 0;
int y = 0;
for (x = 0; x < 9; x++) {
columnbitsToSend = 0;
rowbitsToSend = 0;

for (y = 0; y < 5; y++) {
if (tempLED[x][y] == 1) {
bitWrite(rowbitsToSend, y, HIGH);
}
}

digitalWrite(latchPin, LOW);
bitWrite(columnbitsToSend, x, HIGH);
shiftOut(dataPin, clockPin, MSBFIRST, columnbitsToSend);
shiftOut(dataPin, clockPin, MSBFIRST, rowbitsToSend);
digitalWrite(latchPin, HIGH);
delay(2);
}
}
And I cant fix the problem, because in the column the positive of the fisrt led ,conected to pin 15 in the shift register, dont turn up; and the rest turn up but dont do nothing. Sorry for my English.

17. allysa says:

hi alex, your project is very awesome. thanks for your sharing, i have tried your code by using 2 IC 74HC595 without using darlington array ULN2003, and i modified your code so it can work without darlington array. its work like a charm. but can you help me? what should i change in your code if i want to add more 8×8 dot matrix? thank you so much alex for your help.

• Alex says:

Hi Allysa, to add on an extra 8×8 matrix, you would need to expand the variables like “LEDs”, etc. Then in the lightLED you need to double everything there and add two more shiftOut calls. I would try try focusing on the lightLED function and have it only lighting up single LEDs at a time until you know both 8×8 matrixs work.

18. allysa says:

I Modified your code, and works now with two of 8×8 dot matrix led, check my video at:
http://youtu.be/skBDsUYHXIY
Thanks Alex, soon i will try to add more shift register and matrix led to make 24×8 or more, once again thanks for your help.

• Alex says:

Nice 🙂

• allysa says:

Alex i have lack of RAM issue i’ve checked and it takes a lot of RAM because i’ve tried to check array one by one with IF function, :

if (s==’A’){LEDs[x][y+16] = letterA[x][y];}
if (s==’B’){LEDs[x][y+16] = letterB[x][y];}
if (s==’C’){LEDs[x][y+16] = letterC[x][y];}
if (s==’D’){LEDs[x][y+16] = letterD[x][y];}
if (s==’E’){LEDs[x][y+16] = letterE[x][y]; }
if (s==’F’){LEDs[x][y+16] = letterF[x][y]; }
if (s==’G’){LEDs[x][y+16] = letterG[x][y]; }
if (s==’H’){LEDs[x][y+16] = letterH[x][y]; }
if (s==’J’){LEDs[x][y+16] = letterJ[x][y]; }
if (s==’K’){LEDs[x][y+16] = letterK[x][y]; }
if (s==’L’){LEDs[x][y+16] = letterL[x][y]; }
if (s==’M’){LEDs[x][y+16] = letterM[x][y]; }
if (s==’N’){LEDs[x][y+16] = letterN[x][y]; }
if (s==’O’){LEDs[x][y+16] = letterO[x][y]; }
if (s==’P’){LEDs[x][y+16] = letterP[x][y]; }
if (s==’Q’){LEDs[x][y+16] = letterQ[x][y]; }
if (s==’R’){LEDs[x][y+16] = letterR[x][y]; }
if (s==’S’){LEDs[x][y+16] = letterS[x][y]; }
if (s==’I’){LEDs[x][y+16] = letterI[x][y]; }
if (s==’T’){LEDs[x][y+16] = letterT[x][y]; }
if (s==’U’){LEDs[x][y+16] = letterU[x][y]; }
if (s==’V’){LEDs[x][y+16] = letterV[x][y]; }
if (s==’W’){LEDs[x][y+16] = letterW[x][y]; }
if (s==’X’){LEDs[x][y+16] = letterX[x][y]; }
if (s==’Y’){LEDs[x][y+16] = letterY[x][y]; }
if (s==’Z’){LEDs[x][y+16] = letterZ[x][y]; }

can you tell me another methods to check letter and then calling the array associated with it? btw, thank you Alex for your help.

• Alex says:

One way would be to store each letter in the flash using PGM.

Another method is to store each letter as 8 bytes with each byte representing which LED to light up. If you check my AT Mini Matrix Ctrl code I do this in the function append_text_Matrix (which also uses PGM too).

The setup.c file in AT Mini Matrix Ctrl has the letter to LEDs array:
prog_uchar ledLetters[26][8] PROGMEM = {
{24,8,20,20,20,28,34,119}, // A

• Zach says:

Hey there I was wondering if you could send me and example code for having 2 led matrixs together ? Thanks. Email is jamesbondisthebest@hotmail.com

• Alex says:

Hi Zach,

I don’t have any example code, but you will need to extend the LEDs[8][16] to [8][24] and then you need to go through the for loops and change the correct value to be 8 more. It might be worth scrapping most of the code and making a very simple version to learn about it so then you can understand what’s going on.

19. Zach says:

Hey there I was just wondering if u could put up a detailed picture on how to hook up another 8×8 led matrix and the code so it will work and can I use just 3 shift registers to do this ? Thanks very much

• Alex says:

Hi Zach,

You can either leave the design as being 2 shift registers with a ULN array for each LED matrix or just use 2 shift registers per LED matrix. You’ll need to modify the code and add more shiftout functions. You can add on shift registers to the same pins except for the data in/out one, which you’ll see it flow from shift register 1 to shift register 2, you’ll need to make that same connection from shift register 2 to 3 and 3 to 4.

• Zach says:

Sweet thanks I will try that now what Order do the shift registers have to be in like row to row then column to column ?

• Alex says:

It will need to go row, column, row, column

• Zach says:

So I did that but I still can’t get it to scroll onto the secound led matrix is there any example code that you have for 2 led matrixs I already change all the basic stuff you have mentioned ?

• Alex says:

I don’t have any example code, but basically you will have to increase the arrays, the for loops, etc.
The simplest thing you can do is to modify this:
digitalWrite(latchPin, LOW);
bitWrite(columnbitsToSend, x, HIGH);
shiftOut(dataPin, clockPin, MSBFIRST, columnbitsToSend);
shiftOut(dataPin, clockPin, MSBFIRST, rowbitsToSend);
digitalWrite(latchPin, HIGH);

to this:
digitalWrite(latchPin, LOW);
bitWrite(columnbitsToSend, x, HIGH);
shiftOut(dataPin, clockPin, MSBFIRST, columnbitsToSend);
shiftOut(dataPin, clockPin, MSBFIRST, rowbitsToSend);
shiftOut(dataPin, clockPin, MSBFIRST, columnbitsToSend);
shiftOut(dataPin, clockPin, MSBFIRST, rowbitsToSend);
digitalWrite(latchPin, HIGH);

which will display a duplicate on the other matrix, so you can know if you’ve connected it up right.

• Zach says:

Okay I just got that to work now it duplicates the same letters on both matrixs now from here what do I have to do to get it to scroll from one to the other like for example the letter H starts on one then scrolls over the secound then the next letter ? Like to scroll the message over one to the other ?

20. Zach says:

Sweet I will try that now what Order do the shift registers have to be in like row to row then column to column ?

21. alex says:

What if i have two 8×8 modules chained, what i have to do ?

22. suci says:

good morning, i want to ask you, if i use the LDR into the schematic dot matriks and uln 2803a and 74h595, how to combine into the sketch?

23. nanoBorg88 says:

Sorry for bringing you back to this post. It’s been a long time since you’ve written it, but I thought some things I have to say may be helpful to some.
I saw at the end that you said that you didn’t need the ULN2803, that’s fine and your sketch is working without it. The reason why it might be helpful to have a ULN2803 is so you can sink a lot more current to ground than with the shift register alone.
If instead of flicking one light at a time your sketch could write all the pixels for the column and still be able to sink the 8*20mA of current. This will allow a faster refresh rate on the LED Matrix, as you are no longer addressing each of the 64 LEDs and instead just doing 8 columns.
The 0 state of the shift register would not be able to take the same amount of current.
Sorry if this is written somewhere else, just thought it had to be said.

24. hassan says:

i have a problem in displaying 2 alphabets on 8×8 dot matrix. the problem is that dot matrix shows both alphabets so fast that i donot distinguish both alphabets. i have to add some delay between alphabets… pz elp me in this regard . my program is:

#include
#include
void A()
{
unsigned char a;
unsigned char coloumn []={0x01,0x02,0x3c,0xc0,0x80,0x03,0x3c,0xc0,0xbc,0xc0};
unsigned char row []={0x03,0x01,0xe4,0x01,0x03,0x00,0xfc,0xe1,0x27,0x0f};

for (a=0;a<=9;a++)
{
if (a==5)
delay_ms(1000);}
PORTA= coloumn[a];
PORTB= row[a];
delay_ms(1);
}
}
void main(void)
{
DDRA=(1<<DDA7) | (1<<DDA6) | (1<<DDA5) | (1<<DDA4) | (1<<DDA3) | (1<<DDA2) | (1<<DDA1) | (1<<DDA0);
PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);
DDRB=(1<<DDB7) | (1<<DDB6) | (1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

while (1)
{
A();
}
}

• Alex says:

Hi Hassan,

What you need to do is keep refreshing the letter but then have a counter instead of using delay to change to the next letter, it kind of looks like you are doing that a little but you need to increase the “a” number to say 200 or so, keep testing until you find the right number. You could also increase the delay 1 to say 3-5 or so. Also delay 1000, I’m guessing you want a blank display when the letter changes?

25. Gerard says:

I’m a complete noob at this, but built a matrix using the basic setup you show at the beginning of the video: two shift registers, the first one dedicated for anodes and the second for cathodes (resistors in place). The first two pins of each shift register are left unused as the matrix must be 6×6.

The matrix has a problem. When trying to light a single LED by feeding 1 to the anode and 0 to the cathode, the LED does not necessarily light up. For example, shifting 224 (11011111) and 4 (00100000) to the registers in that order should enable LED 1 from row 1. However, the only result is a very dim and quick flicker in the 6 LEDs that share that are in the same row.

I have double checked the connections and they do not seem to be the problem. Another weird behaviour of the matrix is that the last LED in the row can be lit up individually by shifting 127 (01111111) then 4(00000100) OR 126 then 4. The same happens with all the other rows and I cannot find the logic in it.

Is there something you can do to help with this short description?

• Alex says:

Hi Gerald,

There’s a few things you can try out, perhaps you’ve tried these already.
– If you manually feed in the voltage (without the shift registers) to the LED you wish to light up, does it light?
– How about if you unplug just 1 shift register at a time, for example, the cathode one and then connect the LED to light to ground and see if the shift register acts the way it should? Then try the anode shift register.
– Can you verify the output of the shift registers with a multimeter?

Pictures/Code would help troubleshooting, but the above should hopefully help.

26. tomas says:

hi,

where can i find the code?

Thank you

• Alex says:

Hi,

It’s available here:

• mirza ehsan says:

hello sir i m trying to work out on 2 8×8 led but still i m facing problem to the code please help me and also tell me about the connection for 2nd shift register. thank u

• aya says:

I wanna help ,plz
i tried to make a beating heart, but there is error in the code
heart doesn’t appear
here’s the code :

const int row[8]={2,7,19,5,13,18,12,16};
const int col[8]={6,11,10,3,17,4,8,9};
int pixels[8][8];
int count =1000;
char str[]=”FABCDEDCBA”;
int strLen=sizeof(str);
int ptrChar =0;
typedef bool charMapType[8][8];
const charMapType charBlank = {
{0,0,0,0,0,0,0,0 },
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0} };

const charMapType heart0 = {
{0,0,0,0,0,0,0,0 },
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,1,1,0,0,0},
{0,0,0,1,1,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0} };

const charMapType heart1 = {
{0,0,0,0,0,0,0,0 },
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,1,1,0,0,0},
{0,0,1,1,1,1,0,0},
{0,0,1,1,1,1,0,0},
{0,0,0,1,1,0,0,0},
{0,0,0,0,0,0,0,0} };

const charMapType heart2 = {
{0,0,0,0,0,0,0,0 },
{0,0,0,0,0,0,0,0},
{0,1,1,0,0,1,1,0},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{0,1,1,1,1,1,1,0},
{0,0,1,1,1,1,0,0},
{0,0,0,1,1,0,0,0} };

const charMapType heart3 = {
{0,0,0,0,0,0,0,0},
{0,1,1,0,0,1,1,0},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{0,1,1,1,1,1,1,0},
{0,0,1,1,1,1,0,0},
{0,0,0,1,1,0,0,0},
{0,0,0,0,0,0,0,0} };

const charMapType heart4 = {

{0,1,1,0,0,1,1,0},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{0,1,1,1,1,1,1,0},
{0,0,1,1,1,1,0,0},
{0,0,0,1,1,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0}};

const charMapType *charMap[6] = {&heart0, &heart1, &heart2, &heart3, &heart4, &charBlank};

void setup() {
for (int thisPin =0 ; thisPin < 8 ; thisPin++ ){

pinMode(col[thisPin], OUTPUT);
pinMode(row[thisPin], OUTPUT);
digitalWrite(col[thisPin],HIGH );
}
setupChar();
}
void loop() {
refreshScreen();
if (count–==0){
count = 1000;
setupChar();
}
}
void setupChar(){
char c =str[ptrChar];
int offset = c-'A';
const charMapType *cMap =charMap[offset];

for ( int x =0 ;x<8 ;x++)
{
for ( int y =0 ;y=strlen-1){
ptrChar=0;

}
}

void refreshScreen(){
for(int thisRow=0;thisRow<8;thisRow++){

digitalWrite(row[thisRow],HIGH);
for(int thisCol=0;thisCol<8;thisCol++){
int thisPixel=pixels[thisRow][thisCol];

digitalWrite(col[thisCol],thisPixel);
if(thisPixel==LOW){
digitalWrite(col[thisCol],HIGH);
}
}

digitalWrite(row[thisRow],LOW);
}
}