1088BS led matrix and 74HC595N

Hi to everybody,
may I ask some questions about 8x8 led matrix (1088BS) and shift registers (74HC595N)? :-[

I'd like to create a tetris using two 1088BS (two 8x8 in order to create a matrix with 8 columns and 16 rows).
My questions are:

  • Is it possible to control one 1088BS using a single 74HC595N, or do I need 2 shift registers?
  • Is it possible to control two 1088BS using two 74HC595N, or do I need for example one shift register for columns and two for rows?
  • How many resistors do I need for two 1088BS? 16 resistors?

Thank you in advance!

Don't waste your time.

Do it properly.

Get two of these modules from eBay, using the MAX7219:

Requires three control pins from the Arduino (for any plausible number of modules; they chain together), plenty of examples available (or I could give you some :grinning: ).

Thank you, I've found some on the Internet:

Anyway, can I ask you some more example? :smiley:

Deeder_M:
Thank you, I've found some on the Internet:

Note that if you want to mount them together, you want the type I illustrated, not the clumsy modules pictured in the reference you cited.

That reference is however quite good - I generally use "bit-banging" as they mention, rather then SPI - it is fairly unlikely that the speed difference will be of any significance, even for animation (scrolling).

Deeder_M:
Anyway, can I ask you some more example? :smiley:

Well, here's my test code, set for two displays (I think!). You need to use the matching pin numbers to connect to the displays:

/* Loop scanner demonstration
Code for max 7219 from maxim, reduced & optimised for using multiple 7219 cascaded.
______________________________________

General notes: 

-if using only one max7219, then use maxSingle function to control
the little guy ---maxSingle(register (1-8), collum (0-255))

-if using more then one max7219, and all should work the same, use maxAll
function ---maxAll(register (1-8), collum (0-255))

-if using more than one max7219 and just want to change something
at one little guy, then use maxOne function
---maxOne(Max you wane controll (1== the first one), register (1-8), 
collum (0-255))

/* During initiation, be sure to send every part to every max7219 and then
 upload it.
For example, if you have five max7219's, you have to send the scanLimit 5 times
before you load it-- other wise not every max7219 will get the data. the
function maxInUse  keeps track of this, just tell it how many max7219 you are
using.
*/

#include <Wire.h> 

int dataIn = 2;            // "DIN" on module
int load = 3;              // "CS" on module
int clock = 4;             // "CLK" on module
const int ledPin =  13;    // LED pin number

int maxInUse = 2;          // set how many MAX7219's used
int ledState = LOW;        // initialise the LED

int e = 0;                 // just a varialble

// define max7219 registers
byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity   = 0x0a;
byte max7219_reg_scanLimit   = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;


void putByte(byte data) {
  byte i = 8;
  byte mask;
  while(i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);   // tick
    if (data & mask){            // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    }else{
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);   // tock
    --i;                         // move to lesser bit
  }
}

void maxSingle( byte reg, byte col) {    
//maxSingle is the "easy"  function to use for a     //single max7219

  digitalWrite(load, LOW);       // begin     
  putByte(reg);                  // specify register
  putByte(col);        //((data & 0x01) * 256) + data >> 1); // put data   
  digitalWrite(load,HIGH); 
}

void maxAll( byte reg, byte col) {    // initialize  all  MAX7219's in the system
  int c = 0;
  digitalWrite(load, LOW);  // begin     
  for ( c =1; c<= maxInUse; c++) {
  putByte(reg);                  // specify register
  putByte(col);             //((data & 0x01) * 256) + data >> 1); // put data
    }
  digitalWrite(load,HIGH);
}

void maxOne(byte maxNr, byte reg, byte col) {    
// for adressing different MAX7219's while cascaded

  int c = 0;
  digitalWrite(load, LOW);  // begin     

  for ( c = maxInUse; c > maxNr; c--) {
    putByte(0);             // no operation
    putByte(0);             // no operation
  }

  putByte(reg);             // specify register
  putByte(col);             //((data & 0x01) * 256) + data >> 1); // put data 

  for ( c = maxNr-1; c >= 1; c--) {
    putByte(0);             // no operation
    putByte(0);             // no operation
  }

  digitalWrite(load,HIGH); 
}

void putCol( byte colno, byte coldat) {
// Interprets colno as (zero ref) index in combined array
    byte t;
    t = colno >> 3;
    byte u;
    u = colno & 0x07;
    maxOne(t+1, u+1, coldat);
}


void dispon () {
 maxAll(max7219_reg_shutdown, 0x01);               // Display on
}  

void dispoff () {
 maxAll(max7219_reg_shutdown, 0x00);              // Display off
}  

byte irow = 0;          // Row index
byte icol = 0;          // Column index
byte pattern;           // bit mask
byte lcol;              // left border
byte rcol;              // right border
byte trow;              // top row marker
byte brow;              // bottom row marker

int s_vert;             // Vertical switch
int s_horz;             // Horizontal switch

void worker () {

  if (pattern == 0) pattern = trow;            // pattern must be set
  if (s_vert != 0) {
    if (s_vert == -1) {                     // moving upward
      pattern = pattern >> 1;
      if (pattern == trow) {                   // hit the top
        s_vert = 0; s_horz = 1;
      }
    } else {
      pattern = pattern << 1;               // moving downward
      if (pattern == brow) {                // hit the bottom
        s_vert = 0; s_horz = -1;
      }
    }
    putCol(icol,pattern);              // Show the column.
    return;
  }

  if (s_horz != 0) {
    putCol(icol,0);                    // blank previous column.
    if (s_horz == -1) {                     // moving left
      icol--;
      if (icol == lcol) {                      // hit the side
        s_horz = 0; s_vert = -1;
      }
    } else {
      icol++;                               // moving right
      if (icol == rcol) {                      // hit the side
        s_horz = 0; s_vert = 1;
      }
    }
    putCol(icol,pattern);              // Show the column.
  }
 }
  
// the follow variable is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 60;           // interval at which to step (milliseconds)
long previousMillis = 0;      // will store last time LED was updated


void setup () {

  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);
  pinMode(ledPin, OUTPUT);      

  //Serial begin(9600);
  digitalWrite(13, HIGH);  

//initiation of the max 7219
  maxAll(max7219_reg_displayTest, 0x00); // no display test
  maxAll(max7219_reg_scanLimit, 0x07);      
  maxAll(max7219_reg_decodeMode, 0x00);  // using an led matrix (not digits)
  maxAll(max7219_reg_shutdown, 0x01);    // not in shutdown mode
  for (e=1; e<=8; e++) {        // empty registers, turn all LEDs off 
    maxAll(e,0);
  }
  maxAll(max7219_reg_intensity, 0x08 & 0x0f);  // first argument is intensity value
                                               // range: 0x00 to 0x0f
                                                 
  pattern = 0;
  s_vert = 0;
  s_horz = 1;

// define edges of loop
  lcol = 1;              // left border
  rcol = 14;              // right border
  trow = 0x02;           // top row marker
  brow = 0x40;           // bottom row marker      
      
}  

void loop () {

  unsigned long currentMillis = millis();
 
// Active waiting for next event
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) { ledState = HIGH;  } else { ledState = LOW; }
    // Timed process:
    
    worker();

    // set the LED according to ledState:
    digitalWrite(ledPin, ledState);
    }

}

Bought the MAX7219, now I have to wait shipping time!

While waiting, I'm trying to make two 74HC595N work with a single 8x8 led Matrix.
I've seen that I can connect two shift registers serially using pin9 of one 74HC595N; sending two words I can set outputs of the two 74HC595N.
I think all the connections are right but I have some problem with the code.
Do you have any code/example in the internet to show me, in order to understand what is wrong?

PS. Happy new year! :smiley:

Show us your circuit thus far, then we can talk about code. :wink:

I think all the connections are right

Did you think about the current limits of the '595? Each output pin can only source or sink around 25mA. That current will have to shared between 8 leds, so only about 3mA per led, meaning series resistors of at least 1K. Combined with a 1-in-8 multiplex, each led will receive less than half a milliamp on average, so it will be very dim.

Things can be improved a little if you also have a uln2803 chip available. But don't bother ordering one because your max chip will probably arrive first.

Paul

PaulRB:
Things can be improved a little if you also have a uln2803 chip available. But don't bother ordering one because your max chip will probably arrive first.

Hardly an improvement! An even better reason never to order one - a ULN2x03 is simply a silly option, characteristic of the worst sort of "instructables". An obsolete chip, quite inappropriate to use at 5 V, that it would be really foolish to buy. If you actually wanted to do this, a TPIC6B595 would be the sensible approach.

(Why do I say this? Well, though it is clear that the MAX7219 is the purpose-designed chip on its own so that using two chips is unnecessary, adding yet more chips to overcome the inadequacies of the two really is retrograde and all the more so considering the poor performance of the ULN2x03 using Darlington drivers. I can find virtually no function for which the ULN2003 or ULN2803 is actually suited at this point in time and seriously feel it should drop out of the lexicon of electronic design with as little fanfare as possible, and that we should not mention it in any favourable light.)

@Paul__B, very sorry if I've made your blood pressure worse again, but i did say "if you have one available" and "don't bother purchasing"....

For the more experienced forum members, on the subject of 74hc595 current limits, there are some interesting test results and theories in this thread.

PaulRB:
@Paul__B, very sorry if I've made your blood pressure worse again,

Ah, the medication seems to work pretty well. :grinning:

Here the link used:

Deeder_M:
Here the link used:

http://www.instructables.com/id/Arduino-88-Led-Matrix-Driver-With-2-74HC595-Shift-/step2/Step-2-Placing-it-on-the-breadboard/

Hmm... might have known...

PaulRB:
Hmm... might have known...

The dread "instructable". (Link corrected.)
What is the problem?

Well, it shows a "Fritzing" diagram, but not a circuit schematic as we as engineers expect. Not merely because a schematic is easier to check for problems, but because it fails to educate on how the circuit works and sans that education, followers fail to learn.

Now the principal problem in regard to the circuit, is that the current limiting resistors are missing. This has two consequences; at least one of the chips is being somewhat overloaded, and the display brightness will be inconsistent (as a consequence). Because the LEDs are being driven both on the cathode and anode, this does not constitute a complete short circuit to the CMOS drivers and is perhaps even less than "half" a short circuit, and not continuous (unless most or all LEDs are lit), but is nevertheless outside of the maximum specifications of the chip.

It will usually work - but there are no guarantees of how long or whether the chips will operate correctly in any future use.

I won't mention the bypass capacitors.

Paul__B:
Well, it shows a "Fritzing" diagram, but not a circuit schematic as we as engineers expect. Not merely because a schematic is easier to check for problems, but because it fails to educate on how the circuit works and sans that education, followers fail to learn.

Paul__B:
Now the principal problem in regard to the circuit, is that the current limiting resistors are missing.

Yes I know it is a "Fritzing" diagram and not a circuit schematic, but it was fast to show you the example used. :smiley: Anyway, the link was just a base to define the connections with the 1088BS, but the main tutorial has been the example 2 with two shift registers (and of course the datasheet of the 1088BS).

In particular, I have modified this code, deleting the for cycle from the loop and using two shiftOut(dataPin, clockPin, X):

  • first 8 bits for columns (second shift register);
  • second 8 bits for rows (first shift register).

I used: shiftOut(dataPin, clockPin, 0) and shiftOut(dataPin, clockPin, 128) to light up just a line, 64, 32, 16 for the others (always on the second shiftOut). But I suppose this way is not right, because for example the code doesn't work with 8, 4, 2, 1 (no led is on) and 255 (not all led are on).
Because of this I asked you for any working example.. :grinning:

Deeder_M:
I have modified this code, deleting the for cycle from the loop and using two shiftOut(dataPin, clockPin, X):

  • first 8 bits for columns (second shift register);
  • second 8 bits for rows (first shift register).

Please post your modified code. We will see what can be done.

Deeder_M:
I used: shiftOut(dataPin, clockPin, 0) and shiftOut(dataPin, clockPin, 128) to light up just a line, 64, 32, 16 for the others (always on the second shiftOut). But I suppose this way is not right, because for example the code doesn't work with 8, 4, 2, 1 (no led is on) and 255 (not all led are on).

I think 8, 4, 2 & 1 should also have worked (assuming your shift registers have not already been damaged by the abuse), unless your wiring has an error. Will know better when you post your code. Remember to use code tags!!!!

PaulRB:
Please post your modified code. We will see what can be done.

Here the original code, here the modified:

//Pin connected to ST_CP of 74HC595
int latchPin = A1;
//Pin connected to SH_CP of 74HC595
int clockPin = A0;
////Pin connected to DS of 74HC595
int dataPin = A2;


void setup() {
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);

}

void loop() {
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, 0); 
    shiftOut(dataPin, clockPin, 128);
    digitalWrite(latchPin, 1);
    delay(1000);
}

void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  // This shifts 8 bits out MSB first, 
  //on the rising edge of the clock,
  //clock idles low

//internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);

//clear everything out just in case to
//prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte myDataOut
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights. 
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to myDataOut and a bitmask result 
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000 
    // and proceeds to set pinState to 1.
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {  
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin  
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);
}

PaulRB:
I think 8, 4, 2 & 1 should also have worked (assuming your shift registers have not already been damaged by the abuse), unless your wiring has an error. Will know better when you post your code. Remember to use code tags!!!!

Ahah no no, the led Matrix works.. I tried with another one, the same problem. I will check all the wiring, maybe some cable doesn't work ::slight_smile:

Deeder_M:
maybe some cable doesn't work ::slight_smile:

I hope that is the problem. There is nothing in your code that would make 128 work OK but 8, 4, 2, or 1 not work ok.

Found the problem, there was some wrong wiring... :sweat_smile: now it works!
At the moment, the simple test code is:

//Pin connected to ST_CP of 74HC595
int latchPin = A1;
//Pin connected to SH_CP of 74HC595
int clockPin = A0;
////Pin connected to DS of 74HC595
int dataPin = A2;
int i=0;
int r[9]= {0,1,2,4,8,16,32,64,128}; //array for rows
int c[9]={0,127,191,223,239,247,251,253,254}; //array for columns

void setup() {
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);

}

void loop() {

//single columns
i=0;
  while(i<=8){
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, c[i]); 
    shiftOut(dataPin, clockPin, 255);
    digitalWrite(latchPin, 1);
    delay(200);
    i++;
  }
   
//single rows
i=0;
  while(i<=8){
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, 0); 
    shiftOut(dataPin, clockPin, r[i]);
    digitalWrite(latchPin, 1);
    delay(200);
    i++;
  }
}

void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
  // This shifts 8 bits out MSB first, 
  //on the rising edge of the clock,
  //clock idles low

//internal function setup
  int i=0;
  int pinState;
  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, OUTPUT);

//clear everything out just in case to
//prepare shift register for bit shifting
  digitalWrite(myDataPin, 0);
  digitalWrite(myClockPin, 0);

  //for each bit in the byte myDataOut
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights. 
  for (i=7; i>=0; i--)  {
    digitalWrite(myClockPin, 0);

    //if the value passed to myDataOut and a bitmask result 
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000 
    // and proceeds to set pinState to 1.
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {  
      pinState= 0;
    }

    //Sets the pin to HIGH or LOW depending on pinState
    digitalWrite(myDataPin, pinState);
    //register shifts bits on upstroke of clock pin  
    digitalWrite(myClockPin, 1);
    //zero the data pin after shift to prevent bleed through
    digitalWrite(myDataPin, 0);
  }

  //stop shifting
  digitalWrite(myClockPin, 0);
}

My problem now is that, when rows finish, for a moment all led become on. How could I solve this issue?
Thank you for your support! :smiley:

Take the 0 value out of your row and column arrays and adjust your loops to go from 0 to 7. That may fix it.

Also you can delete that whole shiftOut() function from your sketch because there is one already built for you to use. It has one extra parameter, give it the value MSBFIRST. See ShiftOut()

PaulRB:
Take the 0 value out of your row and column arrays and adjust your loops to go from 0 to 7. That may fix it.

Perfect, it works! :grinning:

PaulRB:
Also you can delete that whole shiftOut() function from your sketch because there is one already built for you to use. It has one extra parameter, give it the value MSBFIRST. See ShiftOut()

I've deleted the function from the code and used the syntax shiftOut(dataPin, clockPin, bitOrder, value) but it doesn't work, maybe two codes are different?