Arduino and Max 7219 Display Driver

Here is a recent demo I did with the MAX 7219 Display Driver and a LED Matrix. I also added some input into the Arduino to control speed and brightness of the display.

wow great job!

i have some max7219's and the other max's laying around, iv'e been meaning to put em together but i'm still working on that damn button pad!

either way great job, please share how you controlled the brightness and the speed, i'd love to know and use it on my displays!

nvrmnd this post....

I wanted to post some of the code used to make my LED Matrix Display with the MAX7219 Chip. I made some tweaks to my code and I use two 200k Pots to control Speed and Brightness of the display.

I used the code found here for the basic set up of the Max7219 chip and removed the extra code I did not use seeing how I only had one chip and one matrix.

//set up pins for max7219 chip//
int dataIn = 13;
int load = 12;
int clock = 11;

//pin and int for display speed//
int inPin = 3;
int val;

//message listed here//
char message[] = "place your demo message here";
int count= sizeof(message);

//data for temp vars and arrays//
char* rowChar[5];
int letterWidth;
int letterHeight;
int payload;
int baseline=1;
int copycount=0;
char incomingByte;
int ipswitch=0;

int spriteBit[8] = {1,2,4,8,16,32,64,128};

int iBuff[8][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,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0},
  {0,0,0,0,0,0,0,0,0}};


//how many MAX7219's you'll use
int maxInUse = 1;    

// just a varialble
int e = 0;           
 
// 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      = 0x08;
byte max7219_reg_digit7      = 0x07;
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) {    
  digitalWrite(load, LOW);       // begin     
  putByte(reg);                  // specify register
  putByte(col);//((data & 0x01) * 256) + data >> 1); // put data   
  digitalWrite(load, LOW);       
  digitalWrite(load,HIGH); 
}
 
// initialize  all  MAX7219's in the system 
void maxAll (byte reg, byte col) {    
  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, LOW);
  digitalWrite(load,HIGH);
}

void setup () {
  pinMode(inPin, INPUT);  
  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);
 
  beginSerial(9600);
  digitalWrite(13, HIGH);  
 
//initiation of the max 7219
  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
  maxAll(max7219_reg_displayTest, 0x00); // no display test
   for (e=1; e<=8; e++) {    // empty registers, turn all LEDs off 
    maxAll(e,0);
  }
  maxAll(max7219_reg_intensity, 0x0f & 0x0f);    // the first 0x0f is the value you can set
                                                  // range: 0x00 to 0x0f
}  


void loop () {
  
     // Loop per letter in message array //
     for (int m=0;m<count;m++){
     bufferLetterMatrix(message[m]);
      
     // Load the row of data into the buffer //
     for (int t=0;t<letterWidth;t++){

     for (int b=0;b<letterHeight;b++){
     iBuff[b+baseline][8]=byte(rowChar[b][t]);
     }
      
     bufferStream(); 
     renderDisplay();

     }     

     
   }

}

continued...

void bufferStream(){
    // move the buffer data one col backwards //
     for (int d=0;d<8;d++) {
     for (int f=0;f<8;f++) { 
     iBuff[d][f]= iBuff[d][f+1];
     } 
     }
}

// Render Buffer - Move bits back one and push to Matrix //  
void renderDisplay(){

     for (int t=0;t<8;t++){
     payload=0;
     for (int b=0;b<8;b++){
     if ( iBuff[t][b] == '1' ) {
     payload=payload+spriteBit[b]; // Add bits based on byte table
     } 
     }
    
    maxSingle(t+1,payload);
        
    }
    
    readSpeedPin();
    checkSerialInput();
}     

void readSpeedPin(){
 
   val = analogRead(inPin) /4 ;   // read the input pin
   Serial.println(val);
   delay(val);

}

void checkSerialInput(){
 
      // send data only when you receive data:
      if (Serial.available() > 0) {
            // read the incoming byte:
                if(ipswitch=0){
                 message[0]= '\0';
                 ipswitch=1; 
                }
            incomingByte = Serial.read(); 
                count=copycount;
                message[copycount]=incomingByte;
                copycount++;
      }else{
  copycount=0;
  ipswitch=0;
}


}

// Switch Case - find letter in message array //
void bufferLetterMatrix(char letter){

   switch (letter) {
    case 'a':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011100";
      rowChar[1]="100010";
      rowChar[2]="111110";
      rowChar[3]="100010";
      rowChar[4]="100010";
      break;
    case 'b':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111100";
      rowChar[1]="100010";
      rowChar[2]="111100";
      rowChar[3]="100010";
      rowChar[4]="111100";
      break;
    case 'c':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011100";
      rowChar[1]="100010";
      rowChar[2]="100000";
      rowChar[3]="100010";
      rowChar[4]="011100";
      break;
    case 'd':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111100";
      rowChar[1]="100010";
      rowChar[2]="100010";
      rowChar[3]="100010";
      rowChar[4]="111100";
      break;
    case 'e':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111110";
      rowChar[1]="100000";
      rowChar[2]="111100";
      rowChar[3]="100000";
      rowChar[4]="111110";
      break;
    case 'f':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111100";
      rowChar[1]="100000";
      rowChar[2]="111100";
      rowChar[3]="100000";
      rowChar[4]="100000";
      break;
    case 'g':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011110";
      rowChar[1]="100000";
      rowChar[2]="100110";
      rowChar[3]="100010";
      rowChar[4]="011100";
      break;
    case 'h':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="100010";
      rowChar[1]="100010";
      rowChar[2]="111110";
      rowChar[3]="100010";
      rowChar[4]="100010";
      break;   
    case 'i':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111110";
      rowChar[1]="001000";
      rowChar[2]="001000";
      rowChar[3]="001000";
      rowChar[4]="111110";
      break;
    case 'j':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="000010";
      rowChar[1]="000010";
      rowChar[2]="000010";
      rowChar[3]="100010";
      rowChar[4]="011100";
      break;
    case 'k':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="100010";
      rowChar[1]="100100";
      rowChar[2]="111000";
      rowChar[3]="100100";
      rowChar[4]="100010";
      break;
    case 'l':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="100000";
      rowChar[1]="100000";
      rowChar[2]="100000";
      rowChar[3]="100000";
      rowChar[4]="111110";
      break;
    case 'm':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="110110";
      rowChar[1]="101010";
      rowChar[2]="101010";
      rowChar[3]="100010";
      rowChar[4]="100010";
      break;
    case 'n':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="110010";
      rowChar[1]="101010";
      rowChar[2]="100110";
      rowChar[3]="100010";
      rowChar[4]="100010";
      break;    
    case 'o':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011100";
      rowChar[1]="100010";
      rowChar[2]="100010";
      rowChar[3]="100010";
      rowChar[4]="011100";
      break;   
    case 'p':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111100";
      rowChar[1]="100010";
      rowChar[2]="111100";
      rowChar[3]="100000";
      rowChar[4]="100000";
      break;
    case 'q':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011110";
      rowChar[1]="100010";
      rowChar[2]="101010";
      rowChar[3]="101010";
      rowChar[4]="011100";
      break;
    case 'r':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111100";
      rowChar[1]="100010";
      rowChar[2]="111100";
      rowChar[3]="100010";
      rowChar[4]="100010";
      break;
    case 's':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011110";
      rowChar[1]="100000";
      rowChar[2]="011100";
      rowChar[3]="000010";
      rowChar[4]="111100";
      break;
    case 't':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111110";
      rowChar[1]="001000";
      rowChar[2]="001000";
      rowChar[3]="001000";
      rowChar[4]="001000";
      break;

continued...

case 'u':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="100010";
      rowChar[1]="100010";
      rowChar[2]="100010";
      rowChar[3]="100010";
      rowChar[4]="011100";
      break;    
    case 'v':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="100010";
      rowChar[1]="100010";
      rowChar[2]="010100";
      rowChar[3]="010100";
      rowChar[4]="001000";
      break;
    case 'w':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="100010";
      rowChar[1]="100010";
      rowChar[2]="101010";
      rowChar[3]="101010";
      rowChar[4]="110110";
      break;
    case 'x':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="100010";
      rowChar[1]="010100";
      rowChar[2]="001000";
      rowChar[3]="010100";
      rowChar[4]="100010";
      break;
    case 'y':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="100010";
      rowChar[1]="010100";
      rowChar[2]="001000";
      rowChar[3]="001000";
      rowChar[4]="001000";
      break;
    case 'z':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111110";
      rowChar[1]="000100";
      rowChar[2]="001000";
      rowChar[3]="010000";
      rowChar[4]="111110";
      break; 
      
      
   case ':': 
      letterWidth=5;
      letterHeight=5;
      rowChar[0]="01100";
      rowChar[1]="01100";
      rowChar[2]="00000";
      rowChar[3]="01100";
      rowChar[4]="01100";
      break; 
   case ')': 
      letterWidth=5;
      letterHeight=5;
      rowChar[0]="1100";
      rowChar[1]="0010";
      rowChar[2]="0010";
      rowChar[3]="0010";
      rowChar[4]="1100";
      break;   
    case '.': 
      letterWidth=5;
      letterHeight=5;
      rowChar[0]="00000";
      rowChar[1]="00000";
      rowChar[2]="00000";
      rowChar[3]="01100";
      rowChar[4]="01100";
      break; 
    case ',': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="000000";
      rowChar[1]="000000";
      rowChar[2]="000000";
      rowChar[3]="001100";
      rowChar[4]="011000";
      break;   
    case '-': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="000000";
      rowChar[1]="000000";
      rowChar[2]="011110";
      rowChar[3]="000000";
      rowChar[4]="000000";
      break; 
    case '*': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="101010";
      rowChar[1]="011100";
      rowChar[2]="110110";
      rowChar[3]="011100";
      rowChar[4]="101010";
      break;   
    case '!': 
      letterWidth=5;
      letterHeight=5;
      rowChar[0]="01100";
      rowChar[1]="01100";
      rowChar[2]="01100";
      rowChar[3]="00000";
      rowChar[4]="01100";
      break; 
    case '|': 
      letterWidth=4;
      letterHeight=5;
      rowChar[0]="0100";
      rowChar[1]="0100";
      rowChar[2]="0100";
      rowChar[3]="0100";
      rowChar[4]="0100";
      break; 
    case '^':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011100";
      rowChar[1]="101010";
      rowChar[2]="110110";
      rowChar[3]="011100";
      rowChar[4]="010100";
      break; 
    case '@':
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="010100";
      rowChar[1]="111110";
      rowChar[2]="111110";
      rowChar[3]="011100";
      rowChar[4]="001000";
      break; 
      
    case '1': 
      letterWidth=5;
      letterHeight=5;
      rowChar[0]="01100";
      rowChar[1]="10100";
      rowChar[2]="00100";
      rowChar[3]="00100";
      rowChar[4]="11110";
      break; 
    case '2': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111100";
      rowChar[1]="000010";
      rowChar[2]="011110";
      rowChar[3]="100000";
      rowChar[4]="111110";
      break;  
    case '3': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011100";
      rowChar[1]="000010";
      rowChar[2]="011110";
      rowChar[3]="000010";
      rowChar[4]="011100";
      break; 
    case '4': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="100010";
      rowChar[1]="100010";
      rowChar[2]="011110";
      rowChar[3]="000010";
      rowChar[4]="000000";
      break; 
    case '5': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011100";
      rowChar[1]="100000";
      rowChar[2]="111100";
      rowChar[3]="000010";
      rowChar[4]="011100";
      break; 
    case '6': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011100";
      rowChar[1]="100000";
      rowChar[2]="111100";
      rowChar[3]="100010";
      rowChar[4]="011100";
      break;   
    case '7': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="111110";
      rowChar[1]="000010";
      rowChar[2]="000100";
      rowChar[3]="001000";
      rowChar[4]="010000";
      break; 
    case '8':
     letterWidth=6;
      letterHeight=5; 
      rowChar[0]="011100";
      rowChar[1]="100010";
      rowChar[2]="011100";
      rowChar[3]="100010";
      rowChar[4]="011100";
      break; 
    case '9': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="011100";
      rowChar[1]="100010";
      rowChar[2]="011110";
      rowChar[3]="000010";
      rowChar[4]="011100";
      break; 
    case '0': 
      letterWidth=6;
      letterHeight=5;
      rowChar[0]="000000";
      rowChar[1]="000000";
      rowChar[2]="000000";
      rowChar[3]="000000";
      rowChar[4]="000000";
      break;

SO to describe the two Pots - you basically put one going into an Analog Input and read that value for the Delay in your code.

void readSpeedPin(){

val = analogRead(inPin) /4 ; // read the input pin
Serial.println(val);
delay(val);

}

In the main loop I call the readSpeedPin function and it does the delay work.

As for the brightness - I just put one going into the reference voltage pin on the Max7219 chip (Pin 18)

I will post the code and my breadboard diagram online soon if anyone is interested in checking it out!

Paul

Paul,
Way cool! Thank you for posting it. It really looks great.

I've adapted what you posted to use the LedControl lib, and it's basically working. However I must turn my display 90 degrees.
I thought I could just make a "row" call instead of a "column" call to flip it. That almost works, but the matrix scrolls backwards, and the letters are mirrored.

I messed around a little with renderDisplay() and managed to get it scrolling in the right direction but the letters were upside down!
(I switched 't' and 'b' on this line - if ( iBuff[t] == '1' )[/color] )
Since what your doing is pretty involved and a little over my head, any pointers you could give me would be appreciated. I think if I could just change the direction of the scroll (from what it is now), I would be OK.
Thanks,
John

thanks for the code and info, once my button pads are done, this is my next project :slight_smile:

I will post the code and my breadboard diagram online soon if anyone is interested in checking it out!

Yes please Paul.

I would love to see your breadboard schematic.

Paul,

Never mind my last post - I figured it out. (or at least I beat it into submission :slight_smile: )
I made the change I mentioned above and then just loaded iBuff "upside down".

So now I have your scrolling message function on a 2 color matrix driven by 2 MAX7221's using the LedControl lib. Here's a bad movie of what it looks like:

Thanks again.

Yeah when I first did the breadboard I ended up reversing the rows from right to left for the scrolling. It was a weird fix in the harware. I have been waiting for more Max7219 chips from Futurelec to add two or three colors to it.

This was my first attempt with this; I have my SparkFun 4x4 button matrix finished - at least soldered this week and will try to integrate the two. I've also updated the breadboard to use a 9volt battery as well. I'll snap a few shots on flickr to outline the components and following sketch for the wiring.

Glad this could help some people out!!

Paul

futurlec... you must have ALOT of time on your hands, becuase your ordering from futurlec...

i've waited almost a week and a half, and no word yet, i had to e-mail them to get some answers, and it turns out that the items marked as in stock, were very out of stock... how great! so i'm hoping to get it next week, hopefully... but you can't beat the price!

That was my first over from Futurlec - and wow it took almost a month to get the 3 Max chips and two DS1307 Realtime Clock boards. You can see a nice picture of my Clock Board below! The price is right though, and if you can deal with the wait it's worth it! The wait also gave me a break so I could play a little World of Warcraft!!

Paul

http://www.flickr.com/photos/cubtastic/2399213575/

lololol LOL!!

i just ordered from futurlec too, and it took about 3 weeks to get the people to finally agree what to send to me, and it took 14 days to ship ( when they said it would be 7-10 days!! ).

and the 8 by 8 led matrix i bought is TINY! about the size of four dimes put in a 2 by 2 squar... i can't compalin i guess cuz i shudda looked at the size, but in the pic it looked huge, so i could only guess...

but if you have time, futurlec gets you the best deals around, and surprisingly the parts seem pretty quality!

but then again, the month lead time till you get it usually pisses people off, like me :slight_smile:

Hiya mate

thx for the code has been a great help to get my matrix scrolling. I am having some issues with it and was wondering if you could help.

i have done char message[] = "jugz";

and all i get in the matrix is jjgggjjgggjjggg and it is scrolling backward and input would be greatly appreciated

I used this chip (well 7221, which is basically the same thing) I stole code from "arduinome" which let me use it without any interrupts (was important for an audio synthesizer, which used its own interrupts.

one thing about these chips, if you use them on the same power supply as anything audio, you have to be very very careful with bypassing and isolation capacitors because they run at 800Hz and can make a lot of PSU noise turning LEDs on and off at that rate.

Because i am running it in a modular synth i had to power the max chip separately (from the same supply though) with 220uf, then 2x 10 ohm resistors (one on 5v and one on ground) then another 220uf cap. it completely got rid of the power supply noise.