Arduino Scrolling 56x8 LED matrix

After several tries, I was able to fit seven 8x8 matrix side-by-side on a breadboard and not have wires crossing over the displays. The key is to put the chips on one side (rather than above or below) the matrices. You can put another 7 driver chips on the right side and double this to a fourteen 8x8 side-by-side matrix!!!

By customizing the breadboard, I was able to rearrange where the power buses are and use them not for power, but to have a common bus for the eight anode rows shared by all displays.

Considering each display require only 16 wires, I was surprised how much time this took to wire up. One thing I learned from this project is that I should not be so stubborn in using the correct wire colors. I ran out of wire of correct length and color and that allowed me to work faster.

Pictures and more info here:

congrats!!!

Impressive! Must be a b*tch to decompile/find errors in your wiring :smiley:

Man, this is great.

Very clean and nice setup

I was wiring up a 8x8 RGB Led Matrix on a breadboard once.

Are these those hellcheap chinese matrizes?

Greets

apogee

Why don't you try to create a pcb board for this? Can you share the code? Congrats!

Meinaart,
I started with just one matrix, got that to work, then run the sketch each time I add another matrix to verify my wiring. I can't imagine having to debug the whole thing at once!

apogee,
It took several tries before I discovered the best place for those chips are to the left and right of the matrix.
Originally I had the chips above each matrix, but when it got beyond 4 matrices, those wires have to travel quite far not to obscure the display. It was tough to decide to start from scratch, but it was the right thing to do.
Yes, I got those matrices for $12/10 from FCB Electronics on ebay, they're in USA so it's fast ship to me (also in USA). They are currently only selling larger $16/10 ones.

federico,
I've never designed a PCB before, I probably should try my hand on a smaller board. :slight_smile:
I've seen so many scrolling matrix, I didn't think it was anything special so I didn't upload the code or show the wiring. I'll review my code and post soon.

Thanks for the encouraging words everyone.
As I said in my blog, this project was a lot of work, but quite satisfying.

federico asked for the code, but I welcome questions and comments from everyone.

I mention this in code, but special thanks goes to aspro648 for laboriously entering the bit patterns for A-Z so we don't have to.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203747843/22

/*
  Arduino 56x8 scrolling LED Matrix
  
Scrolls any message on up to seven (or more?) 8x8 LED matrices.
Adjust the bitmap array below to however many matrices you want to use. 
You can start with as few as two.

The circuit:
* 1 8-bit shift register (SN74HC595) to drive the rows of all displays.
* N power 8-bit shift registers (TPIC6C595) to drive the columns (1 chip per display)
* N 8x8 LED matrix display (rows=Anodes, cold=cathodes)
* N * 8 470ohm resistors, one for each column of each display
* 1 10K resistor
* A big breadboard, or several small ones
* Lots and lots of wires. AT LEAST 16 wires for each display.
* If you plan on driving more than 8 displays, you should add 8 transistors to drive the rows because
potentially you would be lighting up the whole row at one time (56 LEDs at once in my case, 8*n in your case)

Wiring tips:
* Key to success is to put the chips on the left and/or right of the matrix rather than above or below.
This would allow you to run wires above and below the matrix without covering any of them.
* I used several power bus breadboard strips above and below the matrix so all row wires never has to cross the matrix.
* Wire up each matrix one at a time, turning on the Ardunio to verify your work before proceeding to the next matrix.
Correcting your work after you have 32 wires over it is very difficult.
* Circuit is available at: 
http://g33k.blogspot.com/2010/02/arduino-56x8-scrolling-led-matrix.html

Created Feb 2010
By Hari Wiguna
http://g33k.blogspot.com/

Based on things I learn from the Arduino website.
Special credit to aspro648 creating the alphabet that I use.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203747843/22

Creative Commons Attribution-Share Alike 3.0 United States License

*/
// I kept these version notes to show you that it doesn't just all magically happen.  I start simple and keep adding more.
//v01 - Just see if we can drive one matrix, one dot at a time.  Forget multiplexing for now.
//v02 - All three displays show same pattern because they are all tied to same data line.
//v03 - Second and third 595 inputs are tied to outputs of previous, so now shiftout three bytes instead of one.
//v04 - Let's multiplex.  This version has no bleeding, but still flickers quite a bit.
//v05 - Flicker is reduced by using delayMicroseconds() instead of delay().  Flipping both latches HIGH at same time increases brightess of all LEDs.
//v06 - let's animate! (none of this code is in v09, I removed them because they're unrelated to the marquee.
//v07 - We got a scrolling message marquee!
//v08 - Now with SEVEN matrices! 56x8 pixels
//v09 - Add comments and remove experimental code

//-- Columns (Negative Cathodes) --
int latchPin1 = 2; //Arduino pin connected to Green 10 RCK of TPIC6C595
int clockPin1 = 3; //Arduino pin connected to Yellow 15 SRCK of TPIC6C595
int dataPin1 = 4;  //Arduino pin connected to Blue 2 SER IN of TPIC6C595

//-- Rows (Positive Anodes) --
int latchPin2 = 5; //Arduino pinn connected to Green Latch 12 ST_CP / RCK of 74HC595
int clockPin2 = 6; //Arduino pin connected to Yellow Clock 11 SH_CP / SCK of 74HC595
int dataPin2 = 7;  //Arduino pin connected to Blue Data 14 DS / SI of 74HC595

//=== B I T M A P ===
//Bits in this array represents one LED of the matrix
// 8 is # of rows, 7 is # of LED matrix we have
byte bitmap[8][7]; // Change the 7 to however many matrices you want to use.
int numZones = sizeof(bitmap) / 8; // I will refer to each group of 8 columns (represented by one matrix) as a Zone.
int maxZoneIndex = numZones-1;
int numCols = numZones * 8;

//=== F O N T ===
// Font courtesy of aspro648
// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203747843/22
// First char is @, next is A, B, etc.  Only lower case, no symbols.  
// The @ will display as space character.
byte alphabets[][5] = {
  {0,0,0,0,0},
  {31, 36, 68, 36, 31},
  {127, 73, 73, 73, 54},
  {62, 65, 65, 65, 34},
  {127, 65, 65, 34, 28},
  {127, 73, 73, 65, 65},
  {127, 72, 72, 72, 64},
  {62, 65, 65, 69, 38},
  {127, 8, 8, 8, 127},
  {0, 65, 127, 65, 0},
  {2, 1, 1, 1, 126},
  {127, 8, 20, 34, 65},
  {127, 1, 1, 1, 1},
  {127, 32, 16, 32, 127},
  {127, 32, 16, 8, 127},
  {62, 65, 65, 65, 62},
  {127, 72, 72, 72, 48},
  {62, 65, 69, 66, 61},
  {127, 72, 76, 74, 49},
  {50, 73, 73, 73, 38},
  {64, 64, 127, 64, 64},
  {126, 1, 1, 1, 126},
  {124, 2, 1, 2, 124},
  {126, 1, 6, 1, 126},
  {99, 20, 8, 20, 99},
  {96, 16, 15, 16, 96},
  {67, 69, 73, 81, 97},
};

//=== S E T U P ===

void setup() {
  pinMode(latchPin1, OUTPUT);
  pinMode(clockPin1, OUTPUT);
  pinMode(dataPin1, OUTPUT);

  pinMode(latchPin2, OUTPUT);
  pinMode(clockPin2, OUTPUT);
  pinMode(dataPin2, OUTPUT);
  
  //-- Clear bitmap --
  for (int row = 0; row < 8; row++) {
    for (int zone = 0; zone <= maxZoneIndex; zone++) {
      bitmap[row][zone] = 0; 
    }
  }
}

//=== F U N C T I O N S ===

// This routine takes whatever we've setup in the bitmap array and display it on the matrix
void RefreshDisplay()
{
  for (int row = 0; row < 8; row++) {
    int rowbit = 1 << row;
    digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data

    //-- Start sending column bytes -- 
    digitalWrite(latchPin1, LOW);  //Hold latchPin LOW for as long as we're transmitting data

    //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      shiftOut(dataPin1, clockPin1, MSBFIRST, bitmap[row][zone]);
    }

    //-- Done sending Column bytes, flip both latches at once to eliminate flicker
    digitalWrite(latchPin1, HIGH);  //Return the latch pin high to signal chip that it no longer needs to listen for information
    digitalWrite(latchPin2, HIGH);  //Return the latch pin high to signal chip that it no longer needs to listen for information

    //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
    delayMicroseconds(500);
  }
}

// Converts row and colum to actual bitmap bit and turn it off/on
void Plot(int col, int row, bool isOn)
{
  int zone = col / 8;
  int colBitIndex = x % 8;
  byte colBit = 1 << colBitIndex;
  if (isOn)
    bitmap[row][zone] =  bitmap[y][zone] | colBit;
  else
    bitmap[row][zone] =  bitmap[y][zone] & (~colBit);
}

// Plot each character of the message one column at a time, updated the display, shift bitmap left.
void AlphabetSoup()
{
  char msg[] = "THE OBLIGATORY ARDUINO LED MATRIX PROJECT  ";

  for (int charIndex=0; charIndex < (sizeof(msg)-1); charIndex++)
  {
    int alphabetIndex = msg[charIndex] - '@';
    if (alphabetIndex < 0) alphabetIndex=0;
    
    //-- Draw one character of the message --
    // Each character is only 5 columns wide, but I loop two more times to create 2 pixel space betwen characters
    for (int col = 0; col < 7; col++)
    {
      for (int row = 0; row < 8; row++)
      {
        // Set the pixel to what the alphabet say for columns 0 thru 4, but always leave columns 5 and 6 blank.
        bool isOn = 0; 
        if (col<5) isOn = bitRead( alphabets[alphabetIndex][col], 7-row ) == 1;
        Plot( numCols-1, row, isOn); // We ALWAYS draw on the rightmost column, the shift loop below will scroll it leftward.
      }
      
      //-- The more times you repeat this loop, the slower we would scroll --
      for (int refreshCount=0; refreshCount < 10; refreshCount++)
        RefreshDisplay();

      //-- Shift the bitmap one column to left --
      for (int row=0; row<8; row++)
      {
        for (int zone=0; zone < numZones; zone++)
        {
          // This right shift would show as a left scroll on display because leftmost column is represented by least significant bit of the byte.
          bitmap[row][zone] = bitmap[row][zone] >> 1;
          
          // Roll over lowest bit from the next zone as highest bit of this zone.
          if (zone < maxZoneIndex) bitWrite(bitmap[row][zone], 7, bitRead(bitmap[row][zone+1],0));
        }
      }
    }
  }
}

//=== L O O P ===

void loop() {
  AlphabetSoup();
}

Hi! I am trying to do the same thing as you did. I have only one matrix and using 2 74hc595 shift registers.
One shift register controls the anodes and one the cathodes. I have used Bc848 tranzitors for conection to ground.
I am a noobie and for now i have only displayed one letter.

My question is: Could this code work for 74hc595?
and in function Plot do you have to write int x; and int y; ?

One shift register controls the anodes

You can't get enough current sourced from a shift register to power the whole row of LEDs. You need a current source driver like a transistor or FET.

My question is: Could this code work for 74hc595?

Yes, code should work for 74HC595. The terminology for the pins are different, but functionally they shift and latch the same way.

in function Plot do you have to write int x; and int y; ?

:-[ Wow, you're right. It looks like I renamed row and col to x and y and I missed some when I cleanup the code prior to posting here.

I'll fix and re-test tonight. Thanks for letting me know.

I missed renaming row/col parameters while cleaning up the code. Forum won't let me correct the old post, so here's the corrected version of the sketch.

I've re-upload it to the Arduino so I know this version does not have any typos in it. Sorry about that folks. Thanks to Capacea for reporting it.

/*
  Arduino 56x8 scrolling LED Matrix
  
Scrolls any message on up to seven (or more?) 8x8 LED matrices.
Adjust the bitmap array below to however many matrices you want to use. 
You can start with as few as two.

The circuit:
* 1 8-bit shift register (SN74HC595) to drive the rows of all displays.
* N power 8-bit shift registers (TPIC6C595) to drive the columns (1 chip per display)
* N 8x8 LED matrix display (rows=Anodes, cold=cathodes)
* N * 8 470ohm resistors, one for each column of each display
* 1 10K resistor
* A big breadboard, or several small ones
* Lots and lots of wires. AT LEAST 16 wires for each display.
* If you plan on driving more than 8 displays, you should add 8 transistors to drive the rows because
potentially you would be lighting up the whole row at one time (56 LEDs at once in my case, 8*n in your case)

Wiring tips:
* Key to success is to put the chips on the left and/or right of the matrix rather than above or below.
This would allow you to run wires above and below the matrix without covering any of them.
* I used several power bus breadboard strips above and below the matrix so all row wires never has to cross the matrix.
* Wire up each matrix one at a time, turning on the Ardunio to verify your work before proceeding to the next matrix.
Correcting your work after you have 32 wires over it is very difficult.
* Circuit is available at: 
http://g33k.blogspot.com/2010/02/arduino-56x8-scrolling-led-matrix.html

Created Feb 2010
By Hari Wiguna
http://g33k.blogspot.com/

Based on things I learn from the Arduino website.
Special credit to aspro648 creating the alphabet that I use.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203747843/22

Creative Commons Attribution-Share Alike 3.0 United States License

*/
// I kept these version notes to show you that it doesn't just all magically happen.  I start simple and keep adding more.
//v01 - Just see if we can drive one matrix, one dot at a time.  Forget multiplexing for now.
//v02 - All three displays show same pattern because they are all tied to same data line.
//v03 - Second and third 595 inputs are tied to outputs of previous, so now shiftout three bytes instead of one.
//v04 - Let's multiplex.  This version has no bleeding, but still flickers quite a bit.
//v05 - Flicker is reduced by using delayMicroseconds() instead of delay().  Flipping both latches HIGH at same time increases brightess of all LEDs.
//v06 - let's animate! (none of this code is in v09, I removed them because they're unrelated to the marquee.
//v07 - We got a scrolling message marquee!
//v08 - Now with SEVEN matrices! 56x8 pixels
//v09 - Add comments and remove experimental code
//v10 - Fixed search and replace error in Plot.  Thanks to Capacea for catching this error.

//-- Columns (Negative Cathodes) --
int latchPin1 = 2; //Arduino pin connected to Green 10 RCK of TPIC6C595
int clockPin1 = 3; //Arduino pin connected to Yellow 15 SRCK of TPIC6C595
int dataPin1 = 4;  //Arduino pin connected to Blue 2 SER IN of TPIC6C595

//-- Rows (Positive Anodes) --
int latchPin2 = 5; //Arduino pinn connected to Green Latch 12 ST_CP / RCK of 74HC595
int clockPin2 = 6; //Arduino pin connected to Yellow Clock 11 SH_CP / SCK of 74HC595
int dataPin2 = 7;  //Arduino pin connected to Blue Data 14 DS / SI of 74HC595

//=== B I T M A P ===
//Bits in this array represents one LED of the matrix
// 8 is # of rows, 7 is # of LED matrix we have
byte bitmap[8][7]; // Change the 7 to however many matrices you want to use.
int numZones = sizeof(bitmap) / 8; // I will refer to each group of 8 columns (represented by one matrix) as a Zone.
int maxZoneIndex = numZones-1;
int numCols = numZones * 8;

//=== F O N T ===
// Font courtesy of aspro648
// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203747843/22
// First char is @, next is A, B, etc.  Only lower case, no symbols.  
// The @ will display as space character.
byte alphabets[][5] = {
  {0,0,0,0,0},
  {31, 36, 68, 36, 31},
  {127, 73, 73, 73, 54},
  {62, 65, 65, 65, 34},
  {127, 65, 65, 34, 28},
  {127, 73, 73, 65, 65},
  {127, 72, 72, 72, 64},
  {62, 65, 65, 69, 38},
  {127, 8, 8, 8, 127},
  {0, 65, 127, 65, 0},
  {2, 1, 1, 1, 126},
  {127, 8, 20, 34, 65},
  {127, 1, 1, 1, 1},
  {127, 32, 16, 32, 127},
  {127, 32, 16, 8, 127},
  {62, 65, 65, 65, 62},
  {127, 72, 72, 72, 48},
  {62, 65, 69, 66, 61},
  {127, 72, 76, 74, 49},
  {50, 73, 73, 73, 38},
  {64, 64, 127, 64, 64},
  {126, 1, 1, 1, 126},
  {124, 2, 1, 2, 124},
  {126, 1, 6, 1, 126},
  {99, 20, 8, 20, 99},
  {96, 16, 15, 16, 96},
  {67, 69, 73, 81, 97},
};

//=== S E T U P ===

void setup() {
  pinMode(latchPin1, OUTPUT);
  pinMode(clockPin1, OUTPUT);
  pinMode(dataPin1, OUTPUT);

  pinMode(latchPin2, OUTPUT);
  pinMode(clockPin2, OUTPUT);
  pinMode(dataPin2, OUTPUT);
  
  //-- Clear bitmap --
  for (int row = 0; row < 8; row++) {
    for (int zone = 0; zone <= maxZoneIndex; zone++) {
      bitmap[row][zone] = 0; 
    }
  }
}

//=== F U N C T I O N S ===

// This routine takes whatever we've setup in the bitmap array and display it on the matrix
void RefreshDisplay()
{
  for (int row = 0; row < 8; row++) {
    int rowbit = 1 << row;
    digitalWrite(latchPin2, LOW);  //Hold latchPin LOW for as long as we're transmitting data
    shiftOut(dataPin2, clockPin2, MSBFIRST, rowbit);   //Transmit data

    //-- Start sending column bytes -- 
    digitalWrite(latchPin1, LOW);  //Hold latchPin LOW for as long as we're transmitting data

    //-- Shift out to each matrix (zone is 8 columns represented by one matrix)
    for (int zone = maxZoneIndex; zone >= 0; zone--) {
      shiftOut(dataPin1, clockPin1, MSBFIRST, bitmap[row][zone]);
    }

    //-- Done sending Column bytes, flip both latches at once to eliminate flicker
    digitalWrite(latchPin1, HIGH);  //Return the latch pin high to signal chip that it no longer needs to listen for information
    digitalWrite(latchPin2, HIGH);  //Return the latch pin high to signal chip that it no longer needs to listen for information

    //-- Wait a little bit to let humans see what we've pushed out onto the matrix --
    delayMicroseconds(500);
  }
}

// Converts row and colum to actual bitmap bit and turn it off/on
void Plot(int col, int row, bool isOn)
{
  int zone = col / 8;
  int colBitIndex = col % 8;
  byte colBit = 1 << colBitIndex;
  if (isOn)
    bitmap[row][zone] =  bitmap[row][zone] | colBit;
  else
    bitmap[row][zone] =  bitmap[row][zone] & (~colBit);
}

// Plot each character of the message one column at a time, updated the display, shift bitmap left.
void AlphabetSoup()
{
  char msg[] = "THE OBLIGATORY ARDUINO LED MATRIX PROJECT  ";

  for (int charIndex=0; charIndex < (sizeof(msg)-1); charIndex++)
  {
    int alphabetIndex = msg[charIndex] - '@';
    if (alphabetIndex < 0) alphabetIndex=0;
    
    //-- Draw one character of the message --
    // Each character is only 5 columns wide, but I loop two more times to create 2 pixel space betwen characters
    for (int col = 0; col < 7; col++)
    {
      for (int row = 0; row < 8; row++)
      {
        // Set the pixel to what the alphabet say for columns 0 thru 4, but always leave columns 5 and 6 blank.
        bool isOn = 0; 
        if (col<5) isOn = bitRead( alphabets[alphabetIndex][col], 7-row ) == 1;
        Plot( numCols-1, row, isOn); // We ALWAYS draw on the rightmost column, the shift loop below will scroll it leftward.
      }
      
      //-- The more times you repeat this loop, the slower we would scroll --
      for (int refreshCount=0; refreshCount < 10; refreshCount++)
        RefreshDisplay();

      //-- Shift the bitmap one column to left --
      for (int row=0; row<8; row++)
      {
        for (int zone=0; zone < numZones; zone++)
        {
          // This right shift would show as a left scroll on display because leftmost column is represented by least significant bit of the byte.
          bitmap[row][zone] = bitmap[row][zone] >> 1;
          
          // Roll over lowest bit from the next zone as highest bit of this zone.
          if (zone < maxZoneIndex) bitWrite(bitmap[row][zone], 7, bitRead(bitmap[row][zone+1],0));
        }
      }
    }
  }
}

//=== L O O P ===

void loop() {
  AlphabetSoup();
}

Hi, I'm noobie.
Anyone can share the schema?

I want to use 74HC595.
Should I use additional transistor?

Thanks.

I'm trying to build this scrolling LED.
The sketch uploaded successfully and
text scroll smoothly.

But the big problem is the alphabet shown in solid block.
I mean every alphabet are shown as 5x7 dot.

I think there's problem in my wiring.
For hari, please share the schematic.

Many thanks.

Sorry, I've been busy with work.
I don't have a nice schematic, but here is my notes. You need to duplicate the TPIC6C595 circuit several times pumping the output of previous (pin 9) to the next input (pin 4).

Good luck!
hari.mindvision.com/img/56x8ScrollingLEDSchematic.jpg

Hi Hari,

Thanks for sharing that schematic :slight_smile:
I create same wiring like that.
Except, I put resistors in rows, not in cols.
Is that make problem?

Btw, I use 74HC595 for all shift register, not TPIC.

Thanks.

I put resistors in rows, not in cols.
Is that make problem?

Sharing one resistor among up to 56 leds is probably a bad idea because it would alter the brightness of the leds widely depending on how many of those 56 leds are on when that row is on.

Maybe Arduino Scrolling 56x8 LED matrix and Arduino Rolling Multi 16*16 LED Matrix Brick are twinborn brother at some idea. :wink: :wink: LOL

Arduino Rolling Multi 16*16 LED Matrix Brick :
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1273337857

how would I change your code to use matrices who's columns are the anodes, rather than the rows?

Sorry for responding so late.
I may be mistaken, but I believe unlike 74HC595, TPIC6C595 can only drain into ground and cannot supply positive to the anode columns of your matrix.
There's probably a chip similar to TPIC6C595 that would work with your matrix, but I do not know what that is. :frowning:

Hi I am trying to replicate this just using the 74HC595. i have it working perfectly with one 8x8 module. My issue is I have added additional 8x8 Modules but the i cannot get it to output the the additional modules using this code. It just outputs to the first module over and over. i have changed the Bitmap array to reflect the additional modules but nothing has changed. Can someone help me as i am completely stuck.
Cheers
Chris

Right i have managed to get this working (Kind of)... using hari's code I have one slight issue. as each charature crosses from one matrix to the next the first colum seems to stick causing an odd flashing pattern.

Take a look at the following Vid and you will see what i mean.

If anyone has any insight into this I would appreciate it, I am sure it is a code issue but i just cant get to the bottom of it.

Cheers
Chris