Home made LED Matrix (and controlling it)

Hi everyone. First post!

So this weekend I made this: - YouTube

It was a fun project but im having an hard to trying to control each LED individualy so I can light them up to form Shapes or Words.

This is how I connected them:

Im trying to (for example) light up an "X" on each lens.

but I bumped into a problem. I can easily control rows of led's but not so much individual LED's from different rows.

For example, lighting up an "L" character would be something like:

pin 11 HIGH
pin 13 LOW
pin A1 LOW
pin A0 LOW

(that would light up the first row)

However, now to light up the last row of led's I have to make pin 12 and 10 HIGH and because 13 / A1 / A0 are LOW everything will light up... the whole 9 LED's.
=(

This wasn't the best way to connect a matrix of LED's and its now impossible to control each one individually.
Any idea if I can overcome this problem with the programming?

And what would be the best way to easily control the matrix instead of going

pin 13 HIGH / 12 LOW / A1 LOW / A0 LOW
pin X HIGH / LOW / LOW HIGH Yawn yawn yawn....

Thanks! =)

Firstly you must have current limiting resistors in there - the I/O pins may burn out permanently otherwise... You can have the resistors on the anode lines or on the cathode lines, only 3 needed for you 9 LED array, but you have to ensure no pin ever goes above 30mA or so.

Secondly your problem - search for "multiplexing".

Multiplex (with current limit resistors as noted above): write yourself a loop within a loop that will drive 1 of 9 values from a table.
effectively:

for (x = 1 to 3){
anode(x) = high // enable High drive to Anodes in column x
for (y = 1 to 3){
cathode(y) = value(x,y) // drive cathode High (segment off) or Low (segment on) to make the intended display
delay (25) //for example, better would be blin without display
cathode(y) = high // turn off for next segment
next y}
next x}

So you drive position 1,1, on or off as needed,
1,2
1,3
then 2,1
2,2
2,3
then 3,1
3,2
3,3

and repeat
Make the whole thing time based so the characters are display for some many times before swithing to the next character.

Very well!

That makes sense. Ill search more about Multiplexing and try to work it out.
I'll also add the resistors (220ohm should do it) just in case. I'll be supplying 6volts (2x 3volt coin cells).

Im having some problem with the "lastL" var.

according to the serialprint

LAST LED: 2 --------> THIS SHOULD BE 0
Current LED: 2
Last Anode position: 10
Current Anode position: 10
Last Cathode position: 13
Current Cathode position: 13

LAST LED: 7 ---------> THIS SHOULD BE 2
Current LED: 7
Last Anode position: 12
Current Anode position: 12
Last Cathode position: 14
Current Cathode position: 14

void lightup(int led, char lens){

  static int lastL = 0;
  static int lastR = 0;
  int current = led;
  switch(lens){
    
    case 'l':
          //turn the last one off 
      pinMode(leftLensA[lastL], INPUT);
      pinMode(leftLensC[lastL], INPUT);
          //turn on given LED position
      pinMode(leftLensA[lastL], OUTPUT);
      digitalWrite(leftLensA[led], HIGH);
      pinMode(leftLensC[lastL], OUTPUT);
      digitalWrite(leftLensC[led], LOW);
      
      lastL = current;
      
      Serial.print("LAST LED: ");
      Serial.println(lastL);
      Serial.print("Current LED: ");
      Serial.println(led);
      
      Serial.print("Last Anode position: ");
      Serial.println(leftLensA[lastL]);  
      Serial.print("Current Anode position: ");
      Serial.println(leftLensA[led]);  
      
      Serial.print("Last Cathode position: ");
      Serial.println(leftLensC[lastL]);  
      Serial.print("Current Cathode position: ");
      Serial.println(leftLensC[led]);  
      
    break;
  
  case 'r':
     // WORK IN PROGRESS
    break;  
  }
}

I think that if i fix that, everything shoul work just fine.

Any ideas?

sighs... forget it. I solved it.

THIS:
pinMode(leftLensA[lastL], OUTPUT);
digitalWrite(leftLensA[led], HIGH);
pinMode(leftLensC[lastL], OUTPUT);
digitalWrite(leftLensC[led], LOW);

Should be THIS:
pinMode(leftLensA[led], OUTPUT);
digitalWrite(leftLensA[led], HIGH);
pinMode(leftLensC[led], OUTPUT);
digitalWrite(leftLensC[led], LOW);

Last retouches.

Im getting some LED's that should be OFF, dimmly light up. How come?
Is this because i haven't attached the resistors yet? (going to work on that as soon as i finish the coding :slight_smile: )

This may be because of the weak pull-up resistors on Arduino pins. If a pin is configured as an input but the last value written with digitalWrite was HIGH, then the weak pull-ups are enabled (between 20k and 50k according to the datasheet). Do digitalWrite(pin, LOW) when your pin is an input to disable them and have true high-impedance state.

Problem 1:

Hmmm doesn't seem to work MarkT. Can't see any different and there are some LED's dimly lit and some brighter than the others.

void lightup(int led, char lens){

  static int lastL = 0;
  static int lastR = 0;

  switch(lens){
    
    case 'r':
          //turn the last one off 
      pinMode(leftLensA[lastL], INPUT);
        digitalWrite(leftLensA[lastL], LOW);
      pinMode(leftLensC[lastL], INPUT);
        digitalWrite(leftLensC[lastL], LOW);
        
          //turn on given LED position
      pinMode(leftLensA[led], OUTPUT);
      digitalWrite(leftLensA[led], HIGH);
      pinMode(leftLensC[led], OUTPUT);
      digitalWrite(leftLensC[led], LOW);
      lastL = led;
    break;
  
  case 'l':
          //turn the last one off 
      pinMode(rightLensA[lastR], INPUT);
              digitalWrite(rightLensA[lastL], LOW);
      pinMode(rightLensC[lastR], INPUT);
              digitalWrite(rightLensA[lastL], LOW);
              
          //turn on given LED position
      pinMode(rightLensA[led], OUTPUT);
      digitalWrite(rightLensA[led], HIGH);
      pinMode(rightLensC[led], OUTPUT);
      digitalWrite(rightLensC[led], LOW);
      lastR = led;
    break;  
  }
}

Problem 2:

Im having another problem trying to remake the cylon effect using delay(); to create some delay before turning off a column.

Using delay seems to get arduino stuck on the last instruction.
I defined different functions for the columns and rows making it easier to animate them.

using delay after c1() seems to get the function stuck on the last instruction (wich is lightup() a certain LED) making the last LED the only one bright and lit up.

Any idea how i could solve the delay problem? tried the millis hack but didnt work or i got it wrong.
I need each column to stay lit X time before the next one comes up.

// COLUMNS AND LINES
//FOR EASIER MANIPULATION

void c1(){
      lightup(2,'l');
      lightup(5,'l');
      lightup(8,'l');
}

void c2(){
      lightup(1,'l');
      lightup(4,'l');
      lightup(7,'l');
}

void c3(){
      lightup(0,'l');
      lightup(3,'l');
      lightup(6,'l');
}

void c4(){
      lightup(2,'r');
      lightup(5,'r');
      lightup(8,'r');
}

void c5(){
      lightup(1,'r');
      lightup(4,'r');
      lightup(7,'r');
}

void c6(){
      lightup(0,'r');
      lightup(3,'r');
      lightup(6,'r');
}

void l1(){
      lightup(8,'l');
      lightup(7,'l');
      lightup(6,'l');
      lightup(8,'r');
      lightup(7,'r');
      lightup(6,'r');
}

void l2(){
      lightup(5,'l');
      lightup(4,'l');
      lightup(3,'l');
      lightup(5,'r');
      lightup(4,'r');
      lightup(3,'r');
}

void l3(){
      lightup(2,'l');
      lightup(1,'l');
      lightup(0,'l');
      lightup(2,'r');
      lightup(1,'r');
      lightup(0,'r');
}


void cylon(int hop, char orientation){
  switch(orientation){
    //HORIZONTAL CYLON
    case 'h':
      c1();
        delay(hop); //this seems to get C1 stuck on the last lightup() instruction of c1() lighting up only 1 LED brightly.
      c2();
        delay(hop);
      c3();
        delay(hop);      
      c4();
        delay(hop);      
      c5();
        delay(hop);      
      c6();
        delay(hop*2); //Reached end of the goggles, going back after hop*2      
      c5();
        delay(hop);
      c4();
        delay(hop);
      c3();
        delay(hop);
      c2();
        delay(hop);
      c1();
      break;

    //VERTICAL CYLON 
    case 'v':
      l1();
        delay(hop);
      l2();
        delay(hop);
      l3();
        delay(hop*2); //Reached the top of the gogglles, going back after hop*2
      l2();
        delay(hop);
      l1();
      break;
  }
}

Please explain the idea behind changing the pin modes?
The design I proposed had the cathodes being driven high to disable the LEDs. If you change the pin to an input and let if float, the voltage becomes some unknown on the cathode, and +5 on the anode, so if you have efficient LEDs they could appear somewhat on.

You know, I started the code with output / low on the off pins but searching around the foruns I saw the current code im using (turn the off pins to INPUT) and never thought back :slight_smile:

I'll try it later this day and see what happens.

About the delays. Any idea how to solve the problem?
Thanks! =)

CrossRoads:
Please explain the idea behind changing the pin modes?
The design I proposed had the cathodes being driven high to disable the LEDs. If you change the pin to an input and let if float, the voltage becomes some unknown on the cathode, and +5 on the anode, so if you have efficient LEDs they could appear somewhat on.

I'm setting the pins to INPUT to disable them. But you are probably right, thats not grounding them and some voltage might be leaking out.
However I can't seem to figure out your method =/

How would you program the lightup() function?

I tried setting everything to OUTPUT and LOW but that just makes every LED light up for some reason. And still some are brighter than others.

This is what i have atm and need to re-program

void lightup(int led, char lens){

  static int last = 0;

  switch(lens){
    
    case 'r':
          //turn the last one off 
      pinMode(leftLensA[last], OUTPUT);
        digitalWrite(leftLensA[last], LOW);
      pinMode(leftLensC[last], OUTPUT);
        digitalWrite(leftLensC[last], LOW);
          //turn on given LED position
      pinMode(leftLensA[led], OUTPUT);
      digitalWrite(leftLensA[led], HIGH);
      pinMode(leftLensC[led], OUTPUT);
      digitalWrite(leftLensC[led], LOW);
      last = led;
    break;
  
  case 'l':
          //turn the last one off 
      pinMode(rightLensA[last], OUTPUT);
              digitalWrite(rightLensA[last], LOW);
      pinMode(rightLensC[last], OUTPUT);
              digitalWrite(rightLensC[last], LOW);
          //turn on given LED position
      pinMode(rightLensA[led], OUTPUT);
      digitalWrite(rightLensA[led], HIGH);
      pinMode(rightLensC[led], OUTPUT);
      digitalWrite(rightLensC[led], LOW);
      last = led;
    break;  
  }
}

On another note, still trying to figure out how to delay some instructions so i can actually animate the LED's.

FULL SOURCE CODE:

int leftLensA[] = {11,12,10,11,12,10,11,12,10};
int leftLensC[] = {13,13,13,A1,A1,A1,A0,A0,A0};

int rightLensA[] = {8,9,7,8,9,7,8,9,7};
int rightLensC[] = {6,6,6,4,4,4,5,5,5};
int wait = 3000;


void lightup(int led, char lens){

  static int last = 0;


  switch(lens){
    
    case 'r':
          //turn the last one off 
      pinMode(leftLensA[last], OUTPUT);
        digitalWrite(leftLensA[last], LOW);
      pinMode(leftLensC[last], OUTPUT);
        digitalWrite(leftLensC[last], LOW);
          //turn on given LED position
      pinMode(leftLensA[led], OUTPUT);
      digitalWrite(leftLensA[led], HIGH);
      pinMode(leftLensC[led], OUTPUT);
      digitalWrite(leftLensC[led], LOW);
      last = led;
    break;
  
  case 'l':
          //turn the last one off 
      pinMode(rightLensA[last], OUTPUT);
              digitalWrite(rightLensA[last], LOW);
      pinMode(rightLensC[last], OUTPUT);
              digitalWrite(rightLensC[last], LOW);
          //turn on given LED position
      pinMode(rightLensA[led], OUTPUT);
      digitalWrite(rightLensA[led], HIGH);
      pinMode(rightLensC[led], OUTPUT);
      digitalWrite(rightLensC[led], LOW);
      last = led;
    break;  
  }
}



void setup(){  
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);
  
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);  
  digitalWrite(8, LOW);  
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);
  digitalWrite(13, LOW);  
  digitalWrite(A0, LOW);
  digitalWrite(A1, LOW);
  
  Serial.begin(9600); 
}

void loop(){
//  cylon(10, 'v');
//  fu();
    xx();
}

ANIMATIONS.pde

void fu(){

lightup(0, 'l');
lightup(1, 'l');
lightup(2, 'l');
lightup(5, 'l');
lightup(4, 'l');
lightup(8, 'l');

lightup(0, 'r');
lightup(3, 'r');
lightup(6, 'r');
lightup(7, 'r');
lightup(8, 'r');
lightup(5, 'r');
lightup(2, 'r');

}

void xx(){
  lightup(0, 'l');
  lightup(2, 'l');
  lightup(4, 'l');
  lightup(5, 'l');
  lightup(6, 'l');
  lightup(8, 'l');
  
  lightup(0, 'r');
  lightup(2, 'r');
  lightup(4, 'r');
  lightup(5, 'r');
  lightup(6, 'r');
  lightup(8, 'r');
}


// COLUMNS AND LINES
//FOR EASIER MANIPULATION

void c1(){
      lightup(2,'l');
      lightup(5,'l');
      lightup(8,'l');
}

void c2(){
      lightup(1,'l');
      lightup(4,'l');
      lightup(7,'l');
}

void c3(){
      lightup(0,'l');
      lightup(3,'l');
      lightup(6,'l');
}

void c4(){
      lightup(2,'r');
      lightup(5,'r');
      lightup(8,'r');
}

void c5(){
      lightup(1,'r');
      lightup(4,'r');
      lightup(7,'r');
}

void c6(){
      lightup(0,'r');
      lightup(3,'r');
      lightup(6,'r');
}

void l1(){
      lightup(8,'l');
      lightup(7,'l');
      lightup(6,'l');
      lightup(8,'r');
      lightup(7,'r');
      lightup(6,'r');
}

void l2(){
      lightup(5,'l');
      lightup(4,'l');
      lightup(3,'l');
      lightup(5,'r');
      lightup(4,'r');
      lightup(3,'r');
}

void l3(){
      lightup(2,'l');
      lightup(1,'l');
      lightup(0,'l');
      lightup(2,'r');
      lightup(1,'r');
      lightup(0,'r');
}


void cylon(int hop, char orientation){
  switch(orientation){
    //HORIZONTAL CYLON
    case 'h':
      c1();
        delay(hop); //this seems to get C1 stuck on the last lightup() instruction of c1() lighting up only 1 LED brightly.
      c2();
        delay(hop);
      c3();
        delay(hop);      
      c4();
        delay(hop);      
      c5();
        delay(hop);      
      c6();
        delay(hop*2); //Reached end of the goggles, going back after hop*2      
      c5();
        delay(hop);
      c4();
        delay(hop);
      c3();
        delay(hop);
      c2();
        delay(hop);
      c1();
      break;

    //VERTICAL CYLON 
    case 'v':
      l1();
        delay(hop);
      l2();
        delay(hop);
      l3();
        delay(hop*2); //Reached the top of the gogglles, going back after hop*2
      l2();
        delay(hop);
      l1();
      break;
  }
}


void clscr(){
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(7, INPUT);
  pinMode(8, INPUT);
  pinMode(9, INPUT);
  pinMode(10, INPUT);
  pinMode(11, INPUT);
  pinMode(12, INPUT);
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
}

Again, why the pinmode changes?
Turn on anodes. Pulse the cathode from Hi to Lo, pause, then back High
Next set of anodes. Pulse the next cathode from Hi to Lo, pause, then back High
Next set of anodes. Pulse the next cathode from Hi to Lo, pause, then back High

Be sure to drive the Anodes Lo and/or the Cathodes Hi to make the LEDs turn off - any voltage drop across them and the may look on.

Changing the pinmodes is not doing anything for you.

If you don't use pinMode to switch off rows/columns then some LEDs are exposed to 5V reverse voltage which is commonly the 'absolute maximum' rating for LEDs - safer to tristate the pins.

Fine, then turn on the cathode first, and then pulse the anode pins high & low.

    case 'r':
      //turn the last one off 
      digitalWrite(leftLensA[last], LOW);
      digitalWrite(leftLensC[last], LOW);
      //turn on given LED position
      

      digitalWrite(leftLensC[led], LOW);
      digitalWrite(leftLensA[led], HIGH);
      digitalWrite(leftLensA[led], LOW);
      last = led;
    break;

Trying to light up the middle LED turns the whole column on.

O X O
O X O
O X O

X = ON
O = OFF

I can't see how you had them wired from here (access blocked).
You had
A D G
B E H
C F I

where the Anodes of
ABC,
EDF,
GHI
are connected, (columns)
and the cathodes of
ADG,
BEH,
CFI
are connected (rows)?

Then you need to have only 1 cathode at a time on to turn a row on when the Anodes are pulsed high.