matrice (5,24) how to display a message ?

hello , i have some question about LED matrix. (sry for my english , i'm a french student) i want to reproduce a daft punk visor like that http://volpinprops.blogspot.fr/2011/09/daft-punk-helmet-thomas-final.html so i bought 120 red led , and want buy shortly a demultiplexer (1 input 8 output) ( for 5 lane) and 3 multiplexer (8 to 1) 3*8=24 , all column necessary + 1 more (4 - 1) to choose which multiplexer is working . then i can choose which LED is on . But i dont know how and where register the data about letter that i would like to display . i know transpose a letter in bit but where i supposed to register it , and how tell to arduino to display it . the goal is to display any message i want and to scroll it . arduino can do that alone ? Or i have to buy something ? (I have a very small budget) thx for reading , and for your help

Hi Verzat,

I'm sorry but I don't think your approach of using demultiplexers will work. The problem is the leds will be much too dim. If you light only one led at any instant, each led will be off for 119/120 of the time and only on for 1/120 of the time. Your design must light many leds at the same time. For example if you light 15 leds at the same time then they will be on for 1/8 of the time and off for 7/8 of the time, which should be bright enough.

Paul

Yes, we hear it all the time here.

You need to use MAX7219 drivers. Solves all the problems for you - though you have to program them - so then look at the "Parola" project.

Paul__B: You need to use MAX7219 drivers.

There are many other ways to do this, although max7219 is very convenient in many situations and would minimise the hardware required. Programming them is more complex than using simple shift registers, but the Arduino library for max7219 hides all that complexity from the user.

The main problem with max7219 is the cost. If you pay around $10 each, you will almost certainly be getting genuine Maxim chips. Pay around $2 each and they may not be genuine and the quality/reliability may leave something to be desired.

How exactly did you envisage Verzat would use max7219? For a matrix of 5x24 leds, two max7219 would be enough in theory, but the layout would be awkward. Three max7219?

Let me say that I have had no problems at all - so far - with the complete 8 by 8 modules from eBay which must presumably use whatever the “cheap” supply of chips are as the whole module (kit, generally) only costs about $3, give or take. Frankly, it is quite ridiculously absurd to suggest that anyone would even if they could run a manufacturing facility to produce these particular chips and undercut Maxim.

The “instructables” article presumes to use MAX7219s and it would appear that the “Full Monty” uses more like 40 by 8 to match five driver modules (not dissimilar to what is on a breadboard sitting next to me). If you wanted to do it “on the cheap” and use 5 x 24, then it would be just as easy to use three MAX7219s anyway (especially from the coding viewpoint).

The code is actually to my mind, dead easy; just a sequence of subroutines which you use to load the corresponding registers in the MAX7219s; far easier than any other way of doing it such as dozens of shift registers or writing your own multiplexing routines as the chip remembers the data and multiplexes it for you. The “chaining” feature of the MAX7219 facilitates relatively rapid access to any register.

By way of reference, here is my current “play” sketch; I have yet to get into the “Parola” project code. Caveat emptor and all that, obviously I did not write the basic stuff (or all the comments).

/* code for MAX7219 from maxim, 
reduced and optimised for using more then one 7219 in a row,
______________________________________

General notes: 


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

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

-if you are using more than one max7219 and just want to change something
at one little guy, then use the function maxOne
---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;    // the number of the LED pin

int maxInUse = 1;    //change this variable to set how many MAX7219's you'll use
int ledState = LOW;         // ledState used to set 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) {    
//maxOne is for adressing different MAX7219's, 
//while having a couple of them cascaded

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

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

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

  for ( c = maxNr-1; c >= 1; c--) {
    putByte(0);    // means no operation
    putByte(0);    // means 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

// 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 = 40;           // interval at which to blink (milliseconds)
long previousMillis = 0;      // will store last time LED was updated
int scantype = 0;             // switch mode

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.
  }
 }
  

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);    // the first 0x0f is the value you can set
                                                 // range: 0x00 to 0x0f
                                                 
  pattern = 0;
  scantype = 0;
  s_vert = 0;
  s_horz = 1;
  lcol = 1;              // left border
  rcol = 6;              // right border
  trow = 0x02;           // top row marker
  brow = 0x40;           // bottom row marker      
      
}  

void loop () {

  unsigned long currentMillis = millis();
 
  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;
    // Alternate 1

    }
    else {
      ledState = LOW;

    // Alternate 2
    // set the LED with the ledState of the variable:
    // Timed process:
    
    worker();

    }

    digitalWrite(ledPin, ledState);

    }

}

This for one matrix; the effect on a multi-matrix array is somewhat curious!

Paul__B: Let me say that I have had no problems at all - so far - with the complete 8 by 8 modules from eBay which must presumably use whatever the "cheap" supply of chips are as the whole module (kit, generally) only costs about $3, give or take. Frankly, it is quite ridiculously absurd to suggest that anyone would even if they could run a manufacturing facility to produce these particular chips and undercut Maxim.

I have had no problems with the cheap ones either, but I know others have.

Apologies for hijacking Verzat's thread, but check this out: http://www.picaxeforum.co.uk/showthread.php?22481-Real-or-fake&highlight=real+fake

thx all for your answer ! can you link me a tutorial about MAX7219 driver plz ? how connect it each other and to arduino ? and an example of program to display hello with scroll to understand how it working .

I have purchased MAX7219s for $1.25 each plus inexpensive mailing from taydaelectronics.com. Pretty sure they’re not real, and yet they seem to work okay.

Folks seem go on & on about using a library to drive them. If you read the datasheet, they’re quite straightforward. In void setup, you write to a few registers - scan limit (how many digits), no-decode mode (you are not using the internal letter decoding), intensity (brightness), normal mode on (vs shutdown), display test off (vs all LEDs on) - and then in void loop you periodically write to the 8 registers that are the state of the 64 LEDs.
I agree that using 3, set up as 8 digits that are 5 bits each, ignoring the top 3 bits, would be easiest code wise. Set up an array of 24 bytes or however long you want your message to be, and use a pointer to keep track of where the 24 bytes start that you will send out every 50mS to the MAX7219s.
For example this might be the start of the array (each column is 1 byte of memory, the top 3 bits are 0 and not shown - A would be a 1, and O would be 0)
AOOA O AAAA O AOOO AOOO O AAAA O spaces added for clarity
AOOA O AOOO O AOOO AOOO O AOOA O used A & O here for spacing consistency
AAAA O AAAA O AOOO AOOO O AOOA O (hopefully!)
AOOA O AOOO O AOOO AOOO O AOOA O
AOOA O AAAA O AAAA AAAA O AAAA O

1001 0 1111 0 1000 0 1000 0 1111
F44F 0 F555 0 F111 0 F111 0 F11F

hex equivalent of the data, also read vertically, and in the array as:
displayArray = {
0x1f, 0x04, 0x04, 0x1f, 0x00, // H space
0x1f, 0x15, 0x15, 0x15, 0x00, // E space
0x1f, 0x01, 0x01, 0x01, 0x00, // L space
0x1f, 0x01, 0x01, 0x01, 0x00, // L space
0x1f, 0x11, 0x11, 0x1f, 0x00, // O space
};
So at time 0, the first 8 bytes (0-7) go to MAX7219 #0, the next 8 (8-15) go to MAX7219 #1, and the next 8 (16-23) go to MAX7219#2.
50 mS later:
bytes 1-8 go to #0,
bytes 9-16 go to #1,
bytes 17-24 go to #2.
and so on.
Eventually you get to the end of your array, say it was 48 bytes (0 to 47) and then wrapped around:
bytes 28-35 go to #0
bytes 36-43 go to #1
bytes 44-47 and 0-3 go to #2 (with 3 other bytes having wrapped around already)

DIGIT pins are the common cathodes to the columns
SEGMENT pins are anode drivers that go to all 8 anodes in each row.

Connecting to the Arduino is simple:
SCK to CLK,
MOSI to DIN,
SS to Latch.
And I use the built in SPI hardware to make the transfers:

for (registerNumber =1 ; registerNumber<9; registerNumber = registerNumber +1){
digitalWrite (SSpin, LOW);
SPI.transfer(registerNumber); // from Table 2, page 2
// columnNumber will be the starting position - update it outside of this loop
// example 1, 9, 17; then 2, 10, 18; then 3,11,19
SPI.transfer(displayArray[columnNumber + registerNumber]); 
digitalWrite (SSpin, HIGH);
}

Put that in a loop for each MAX7219, and increment registerNumber & columnNumber for the data you are sending out.

I found it easier to have a chip select for each device and only writing the 8 bytes for each device vs passing all data thru all devices, but that could just be me being tired and coding late at night too.
I also would use a blank column between characters in the array, can have the code insert that if needed; or, leave it out and just put a space between words.

thx again but i still have a problem with link between arduino and MAX7219 .
in my arduino UNO i dont have Din CLK load CS . i see on the left IOREF ,RESET , 3.3V , 5V, gnd , gnd , Vin , Ao-to-A6
and on the right AREF , gnd , 13 ,12, … ,2, tx->1 ,rx<-0.
so what is clk what is load and what is din ?
thanq you

Verzat:
in my Arduino UNO I don’t have Din CLK load CS.

Oh yes you do!

Verzat:
I see on the left IOREF ,RESET , 3.3V , 5V, gnd , gnd , Vin , Ao-to-A6 and on the right AREF , gnd , 13 ,12, … ,2, tx->1 ,rx<-0.
so what is clk what is load and what is din ?

You probably didn’t look at the specimen code I posted - since you weren’t thinking at the time of using it. The code includes definitions for which pins are used for each of these functions, and they are not immutable - you can choose which pins to use for each function and as long as the pins you use match up with the specifications in the code itself and do not conflict with any other function, it will work.

Of course, this is not always the case, but as has been mentioned here, you do not need to use libraries to perform these shift register functions in software and it is often easier to see the actual code that is in use. If you are employing hardware in the chip to perform serial transfers (SPI or I2C) then the hardware is tied to certain pins.

Connecting to the Arduino is simple: SCK to CLK, MOSI to DIN, SS to Latch.

SCK = Arduino 13 MOSI = Arduino 11 SS = Arduino 10

Then SPI.transfer:

digitalWrite (SSpin, LOW);
SPI.transfer (registerNumber); // from Table 2, page 2
SPI.transfer (dataToSend);
digitalWrite (SSpin, HIGH);

thanq you very much ! could you please send me an exemple for display an "A" which scroll with a single MAX7219 . there are several parts of the code that I don't understand. my biggest problem is , where say to arduino what i want display

up, i'm still working on my project and i have finished to build my led matrix (7*8 finaly ^^"). no problème to connect everything.

i followed this tuto to connect https://www.pjrc.com/teensy/td_libs_Matrix.html#connections and this one http://playground.arduino.cc/Main/MAX72XXHardware to know how connect resistor and condensator . but i have a probleme : when everything is connected and i use this code : http://linksprite.com/wiki/index.php5?title=LED_Matrix_Kit all my led are switch on and dont blink. the most weird thing is when i disconnect my 5V pin of arduino AND the gnd pin , leds are still brighting (but weakly) and blink but i cant read any letter . have you any idea about origine of the problem ? thank you