Led Matrix 8x8 x5 max7219

Hello Everyone!

I am still relatively new (well 2 years with no real progress) to Arduino programming and I have a question.

I have put together 5 8x8 led matrix's (matrices?) and have stumbled my way through a couple of simple scrolling animations. They are very large and have taken me a little bit of tom foolery to compile. I was wondering if there were a way to label the animations so that they loop individually until a button is pressed?

I will post my code below for anyone that could help. keep in mind that the animations are still somewhat incomplete as they would not facilitate a smooth loop, Also the code is copied from.... somewhere, I wish I could remember to give credit where credit is due (it has been a while since i started this project)

Thanks in advance!

int dataIn = 2;
int load = 3;
int clock = 4;
 
int maxInUse = 5;    //change this variable to set how many MAX7219's you'll use
 
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, LOW);       // and load da shit
  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, LOW);
  digitalWrite(load,HIGH);
}
 
void maxOne(byte maxNr, byte reg, byte col) {    
//maxOne is for adressing different MAX7219's,
//whilele 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, LOW); // and load da shit
  digitalWrite(load,HIGH);
}
 
 
void setup () {
 
 
  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 () {
 
  
 //Animation 1
  
  
  maxOne(1,1,B00010000); 
  delay(30);
  maxOne(1,2,B00010000);
  delay(30);
  maxOne(1,3,B00010000);
  delay(30);
  maxOne(1,4,B00010000);
  delay(30);
  maxOne(1,5,B00010000);
  delay(30);
  maxOne(1,6,B00010000);
  delay(30);
  maxOne(1,7,B00010000);
  delay(30);
  maxOne(1,8,B00010000);
  delay(30);
 
  delay(30);
  maxOne(2,1,B00010000); 
  delay(30);
  maxOne(2,2,B00010000);
  delay(30);
  maxOne(2,3,B00001000);
  delay(30);
  maxOne(2,4,B00000100);
  delay(30);
  maxOne(2,5,B00000010);
  delay(30);
  maxOne(2,6,B00000100);
  delay(30);
  maxOne(2,7,B00001000);
  delay(30);
  maxOne(2,8,B00010000);
  delay(30);
  
  delay(30);
  maxOne(3,1,B00100000); 
  delay(30);
  maxOne(3,2,B01000000);
  delay(30);
  maxOne(3,3,B00100000);
  delay(30);
  maxOne(3,4,B00010000);
  delay(30);
  maxOne(3,5,B00010000);
  delay(30);
  maxOne(3,6,B00010000);
  delay(30);
  maxOne(3,7,B00010000);
  delay(30);
  maxOne(3,8,B00010000);
  delay(30);
  
  delay(30);
  maxOne(4,1,B00010000); 
  delay(30);
  maxOne(4,2,B00010000);
  delay(30);
  maxOne(4,3,B00010000);
  delay(30);
  maxOne(4,4,B00001000);
  delay(30);
  maxOne(4,5,B00000100);
  delay(30);
  maxOne(4,6,B00000010);
  delay(30);
  maxOne(4,7,B00000100);
  delay(30);
  maxOne(4,8,B00001000);
  delay(30);
  
  delay(30);
  maxOne(5,1,B00010000); 
  delay(30);
  maxOne(5,2,B00100000);
  delay(30);
  maxOne(5,3,B01000000);
  delay(30);
  maxOne(5,4,B00100000);
  delay(30);
  maxOne(5,5,B00010000);
  delay(30);
  maxOne(5,6,B00010000);
  delay(30);
  maxOne(5,7,B00010000);
  delay(30);
  maxOne(5,8,B00010000);
  delay(30);
  
  
  //Animation 2
  
  
 delay(30);
  maxOne(1,1,B00011000); 
  delay(30);
  maxOne(1,2,B00011000); 
  delay(30);
  maxOne(1,1,B00000000);
  delay(30);
  maxOne(1,3,B00011000);
  delay(30);
  maxOne(1,2,B00000000);
  delay(30);
  maxOne(1,4,B00011000);
  delay(30);
  maxOne(1,3,B00000000); 
  delay(30);
  maxOne(1,5,B00011000);
  delay(30);
  maxOne(1,4,B00000000);
  delay(30);
  maxOne(1,6,B00011000);
  delay(30);
  maxOne(1,5,B00000000);
  delay(30);
  maxOne(1,7,B00011000);
  delay(30);
  maxOne(1,6,B00000000);
  delay(30);
  maxOne(1,8,B00011000);
  delay(30);
  maxOne(1,7,B00000000);
  delay(30);
  maxOne(2,1,B00011000); 
  delay(30);
  maxOne(1,8,B00000000);
  delay(30);
  
  
  maxOne(2,2,B00011000); 
  delay(30);
  maxOne(2,1,B00000000);
  delay(30);
  maxOne(2,3,B00011000);
  delay(30);
  maxOne(2,2,B00000000);
  delay(30);
  maxOne(2,4,B00011000);
  delay(30);
  maxOne(2,3,B00000000); 
  delay(30);
  maxOne(2,5,B00011000);
  delay(30);
  maxOne(2,4,B00000000);
  delay(30);
  maxOne(2,6,B00011000);
  delay(30);
  maxOne(2,5,B00000000);
  delay(30);
  maxOne(2,7,B00011000);
  delay(30);
  maxOne(2,6,B00000000);
  delay(30);
  maxOne(2,8,B00011000);
  delay(30);
  maxOne(2,7,B00000000);
  delay(30);
  maxOne(3,1,B00011000); 
  delay(30);
  maxOne(2,8,B00000000);
  delay(30);
 
  
  maxOne(3,2,B00011000); 
  delay(30);
  maxOne(3,1,B00000000);
  delay(30);
  maxOne(3,3,B00011000);
  delay(30);
  maxOne(3,2,B00000000);
  delay(30);
  maxOne(3,4,B00011000);
  delay(30);
  maxOne(3,3,B00000000); 
  delay(30);
  maxOne(3,5,B00011000);
  delay(30);
  maxOne(3,4,B00000000);
  delay(30);
  maxOne(3,6,B00011000);
  delay(30);
  maxOne(3,5,B00000000);
  delay(30);
  maxOne(3,7,B00011000);
  delay(30);
  maxOne(3,6,B00000000);
  delay(30);
  maxOne(3,8,B00011000);
  delay(30);
  maxOne(3,7,B00000000);
  delay(30);
  maxOne(4,1,B00011000);
  delay(30);
  maxOne(3,8,B00000000);
  delay(30);
  
   
  maxOne(4,2,B00011000); 
  delay(30);
  maxOne(4,1,B00000000);
  delay(30);
  maxOne(4,3,B00011000);
  delay(30);
  maxOne(4,2,B00000000);
  delay(30);
  maxOne(4,4,B00011000);
  delay(30);
  maxOne(4,3,B00000000); 
  delay(30);
  maxOne(4,5,B00011000);
  delay(30);
  maxOne(4,4,B00000000);
  delay(30);
  maxOne(4,6,B00011000);
  delay(30);
  maxOne(4,5,B00000000);
  delay(30);
  maxOne(4,7,B00011000);
  delay(30);
  maxOne(4,6,B00000000);
  delay(30);
  maxOne(4,8,B00011000);
  delay(30);
  maxOne(4,7,B00000000);
  delay(30);
  maxOne(5,1,B00011000); 
  delay(30);
  maxOne(4,8,B00000000);
  delay(30);
  
  maxOne(5,2,B00011000); 
  delay(30);
  maxOne(5,1,B00000000);
  delay(30);
  maxOne(5,3,B00011000);
  delay(30);
  maxOne(5,2,B00000000);
  delay(30);
  maxOne(5,4,B00011000);
  delay(30);
  maxOne(5,3,B00000000); 
  delay(30);
  maxOne(5,5,B00011000);
  delay(30);
  maxOne(5,4,B00000000);
  delay(30);
  maxOne(5,6,B00011000);
  delay(30);
  maxOne(5,5,B00000000);
  delay(30);
  maxOne(5,7,B00011000);
  delay(30);
  maxOne(5,6,B00000000);
  delay(30);
  maxOne(5,8,B00011000);
  delay(30);
  maxOne(5,7,B00000000);
  delay(30);
  
 
 //Animation 3
 
 
  maxOne(1,1,B11111111); 
  delay(50);
  maxOne(1,2,B11111111); 
  delay(50);
  maxOne(1,1,B00000000); 
  maxOne(1,3,B11111111); 
  delay(50);
  maxOne(1,2,B00000000); 
  maxOne(1,4,B11111111); 
  delay(50);
  maxOne(1,3,B00000000); 
  maxOne(1,5,B11111111); 
  delay(50);
  maxOne(1,4,B00000000); 
  maxOne(1,6,B11111111); 
  delay(50);
  maxOne(1,5,B00000000); 
  maxOne(1,7,B11111111); 
  delay(50);
  maxOne(1,6,B00000000); 
  maxOne(1,8,B11111111); 
  delay(50);
  maxOne(1,1,B11111111);
  maxOne(1,7,B00000000); 
  maxOne(2,1,B11111111); 
  delay(50);
  maxOne(1,2,B11111111);
  maxOne(1,8,B00000000); 
  maxOne(2,2,B11111111); 
  delay(50);
    
  //
  delay(30);
 
}

Sorry had to trim my massive code, apparently it was over 9500 characters and i cut out about 2/3 of it XD

You should be creating arrays for the bit pattern and the delay (either 2 arrays or an array of a structure with the data in it). This then allows you to create a tight loop to process each array element to do what you want. You also don't need to leave a delay between outputting to the different modules.

If you look at the Parola link below you will see how fast these devices can be driven (video) and you can look at the code (not beginner's level though, but you may get some hints). The examples that come with the MD_MAX72XX may also help you understand what is going on.

Thank you marco_c, but I did some reading on arrays and I am not sure I understand how to apply it to what I am doing?? I looked at arduino's tutorial on arrays and they directed to an example of Knight Rider but it isn't exactly the same as what I would be doing... I don't think at least. http://www.arduino.cc/en/Tutorial/KnightRider

I think i see what you mean about the delay between modules, that was just an error on my part for the animation. It is barely noticeable, but thank you for pointing it out :).

Maybe if you don't mind giving me a small example of something that is more relevant to my situation, if that is not asking too much. I would really appreciate it.

Oh and if anyone is interested this is for a Daft Punk helmet, i have been meaning to do one for years, now seemed like as good of a time as any with the recent release of their new album.

Thanks again :slight_smile:

Simplistically, you could take each of your animations and put them in a separate function (animation1, animation2, etc). In the main loop you then check if a button is pressed and if so, increment a variable with wraparound. The correct animation is then run through a case statement. Something like this:

void animation0()
{
// stuff in here
}

void animation1()
{
}
// etc for as many animations as you want, lets say MAX_ANIMATION

void loop()
{
  static int anim = 0;

  switch (anim)
  {
  case 0:   animation0();  break;
  case 1:  animation1(); break;
// etc
  default: anim = 0;  // in case things go crazy :-)
  }

  // check if the button is pressed
  if (buttonpressed)  // substitute your code here
    anim = (anim + 1) % MAX_ANIMATION;
}

I would encourage you to do this step as it will create a basic flow. However, what you will quickly find is that the animations changing is hard because the button is only detected once an animation is over (you are use the delay() function in the animation function), whereas as a user you would expect to have the change happen as soon as you press the button.

In order for the software to do what you expect you will need to use techniques shown in the BlinkWithoutDelay example, checking the timer rather than calling delay(). At that point you may find it more convenient to have the animation bit patterns as arrays because you need to remember where you were in the animation (ie, the array index of the last pattern sequence) every time the animation function is called. You set up the bit pattern array like this:

uint8_8 pattern0 [][8] = 
{
  { B00010000,B00010000,B00010000,B00010000,B00010000,B00010000,B00010000,B00010000 },
  { B00010000,B00010000,B00001000,B00000100,B00000010,B00000100,B00001000,B00010000 },
// etc - you get the idea
}

Then your code changes to be one animation routine called with a different pattern array (ie, the code becomes general and the data tells it what to do). This makes managing your code much easier and changing patterns becomes easier as well.

Hopefully this is enough of an explanation to get you going.

Wow! Thank you very much, I really appreciate you laying it out a simple as you could. This will be a Great help i am sure of it XD

I will keep you posted with any progress I have made and probably post a small working (hopefully) sample once I have finished, for anyone else who wants to attempt a similar project. And maybe I will post some pictures of the project too.

Cute animation!

Tried it with one panel I have at work, and three at home. I have a five panel here, but going to bed now - try it tomorrow.

May have a play with the code at some stage ...

Thanks :slight_smile:

The animation isn't exactly complete, I had to chop each one about 2/3 due to the massive size of my code XD. I have each one loop at least once because I did not know how to make it loop, and i also have about 8 animations total including a "randomization" pattern. Now i say "randomization" because i had to animate it rather than an actual random pattern, it just gives the appearance of a random pattern.

If anyone is interested in the full animation please do not hesitate to ask, i have no problems in sharing any of my work or progress i have made or will make.

Don't forget that you can always attach a file to tthe post, it does not have to be text in the post itself. Look at the additional options menu at the bottom of the post edit text box.