RGB LED is not working properly with multiplexer

Hello everyone,
I am planning to do a board game with RGB LEDs, I've installed everything using only 4 RGB LEDs, however I want to use more (about 25 RGB LEDs), and each one has 3 output pins for R, G and B.

So in order to do that I am using 16 channel analog multiplexer.

I never used a multiplexer, and I got the code online, I tried to light up one RGB LED, but it's not working properly. I'm not sure what I'm doing wrong. As far as I know, I should get the right channel of the pin with s0, s1, s2 & s3 then write the value to sig.
At first the RGB did not light up, then I put delay(250), and it started lighting up each color separately (R then delay by 250 and G ... ).

this is the code:

int s3 = 6;
int s2 = 7;
int s1 = 8;
int s0 = 9;
  int muxChannel[16][4]={
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10
    {1,1,0,1}, //channel 11
    {0,0,1,1}, //channel 12
    {1,0,1,1}, //channel 13
    {0,1,1,1}, //channel 14
    {1,1,1,1}  //channel 15
  }; 

int controlPin[] = {s0, s1, s2, s3};
int sig = 5;
int led3[6] = {8, 9, 10, 0, 0, 0};

void setup()
{
  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
   digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  pinMode(sig, OUTPUT);
Serial.begin(9600); 
 }
void loop()
{    setCol(led3, 150, 0, 0); 
delay(100);
}

void setCol(int* led, int r, int g, int b) {
    for(int i = 0; i < 4; i ++){
      digitalWrite(controlPin[i], muxChannel[led[0]][i]);
    }
    analogWrite(sig, r);
    delay(250);
    for(int i = 0; i < 4; i ++){
      digitalWrite(controlPin[i], muxChannel[led[1]][i]);
    }
    analogWrite(sig, g);
    delay(250);
    for(int i = 0; i < 4; i ++){
      digitalWrite(controlPin[i], muxChannel[led[2]][i]);
    }
    analogWrite(sig, b);
   delay(250);
}

how do I make this work, how can I connect RGB LED with this multiplexer properly?
Tried hours looking online but no luck.
Thank you

Driving LEDs with a multiplexer is not the most sensible approach.

then I put delay(250), and it started lighting up each color separately

Yes it would, a quarter of a second is a long time, make it shorter and your eyes have time to integrate the fast flashing so it looks continuous. But the big snag with multiplexing is that each LED is only on for a fraction of a time. With 25 LEDs then each only is only on for one twenty-fifth of the time. So they will be very dim.

The proper way to do this is to use a shift register and the ShiftPWM library at http://www.elcojacobs.com/shiftpwm/.

Or alternatively use a PWM generator chip, like five of these 16 channel 12 bit pwm

Or even simpler use a WS2812 strip of LEDs or the separate ones you can buy, both PCB mounted and wire ended.

If you want round 5mm LEDs, look for "apa106" or "pl9823". These are compatible with code written for ws2812 and are wired in the same way.

Grumpy_Mike:
Driving LEDs with a multiplexer is not the most sensible approach.
Yes it would, a quarter of a second is a long time, make it shorter and your eyes have time to integrate the fast flashing so it looks continuous. But the big snag with multiplexing is that each LED is only on for a fraction of a time. With 25 LEDs then each only is only on for one twenty-fifth of the time. So they will be very dim.

The proper way to do this is to use a shift register and the ShiftPWM library at http://www.elcojacobs.com/shiftpwm/.

Or alternatively use a PWM generator chip, like five of these 16 channel 12 bit pwm

Or even simpler use a WS2812 strip of LEDs or the separate ones you can buy, both PCB mounted and wire ended.

I don't get it, so there is no way to fix this with a multiplexer ? I have already bought 4 :(.
I mean is it impossible ?

Also, would this work if I split the R G B wires on three multiplexers ? (like R on one multiplexer, G on the other, and B on the 3rd) ??

haytam111:
I don't get it, so there is no way to fix this with a multiplexer ? I have already bought 4.
I mean is it impossible ?

So, you went out and bought four of something without first coming here and asking whether it was a practical way to do the job?

Otherwise known as the "XY Problem". :roll_eyes:

Now you have firstly failed to explain what analog multiplexer it was you bought. Was it a 74HC4067 with an "on" resistance of 80 Ohms, or the obsolete CD4067 with an "on" resistance of 470 Ohms?

I can't entirely criticise the idea as I did exactly this, using a CD4051 multiplexer to switch one of eight LEDs back in the 1980s. :grinning: It "kind of" worked at the time. So since a 470 Ohm resistor is not an entirely unusual value for a LED resistor, if you want to light one LED, that is not too bad. But when you want to multiplex them, one sixteenth of that average current will indeed be rather dim.

Clearly for your project, you need to use the WS2812 "NeoPixels" or APA106.

The LEDs would be a little brighter, but still pretty dim.

This is what I suggest you try using the components you have (at least as far as we know, you have given no details, so I will assume the LEDs are 5mm common cathode, the multiplexers are 74hc4067 and you are using an Uno).

The Uno has 6 PWM pins. Connect a series resistor to each, value chosen to limit the current to around 6mA. The value for the pins connected to red LEDs will need to be higher than those for blue & green. Take account of the 70~80R resistance of the multiplexer.

Connect 3 pwm pins + series resistors on parallel to the anodes of 13 LEDs. Connect the other 3 to the remaining 12 LEDs.

Connect the common cathodes of the 13 LEDs to the inputs of a multiplexer. Connect the cathodes of the other 12 LEDs to a second multiplexer. Connect the multiplexer outputs to ground.

Connect the select pins of each multiplexer together and to 4 Arduino digital outputs.

Now you can multiplex with a 1 in 13 ratio. The average current per led will be around 0.5mA per led, which should be visible in normal indoor light levels.

I was thinking an approach like this, with MAX7219 driving 16 RGB LEDs, so you'd use two MAX7219 to support up to 32 RGB LEDs.
MAX7219 works by driving the 8 anode lines, and 1 cathode line, at at time.
It multiplexes at 800 Hz, so any On LEDs all look to be on together.
If the anodes are split like I show, then Register1 will control 2 LEDs, Register2 will control 2, etc.
Bits x654x210 will be the active colors, so for each LED's 3 bits:
000 is off,
001 = Red,
010 = Green
011 = Red +Green
100 = Blue
101 = Red + Blue
110 = Green + Blue
111 = Red + Green + Blue

Need 10K resistor,
0.1uF cap,
10uF
for each chip.

Can't get the 255 levels of brightness for each color, just the 8 colors with 15 levels of brightness for the chip, that may be enough for the OP's needs.

Another option for common anode RGB LEDs is WS2801, need 1 per RGB LED,
or WS2803, can control 6 RGB LEDs per chip.
Only place I have to seen to get those is ebay, place out of Niagara Falls sells them.

haytam111:
I don't get it, so there is no way to fix this with a multiplexer ? I have already bought 4 :(.
I mean is it impossible ?

I'm all in favour of experimenting and trying things out to find ways of doing things, whatever works. Sometime you discover things that do what you need that others have said should not work, sometimes you get smoke, sometimes you have parts to add to your collection for a later project. Just make sure you learn from the experience. If you can't get a satisfactory result from the parts you have then time to try a different approach, just have fun experimenting.

Well said, Perry. I would also add "ask for advice before you spend your money"!

I don't get it, so there is no way to fix this with a multiplexer ?

Yes, your idea was flawed from the outset by forgetting, or not knowing, that the duty cycle of the multiplexing meant that the results would be far too dim. The other soloution that has not been mentioned so far is using an addressable latch, but it is not better than those already mentioned.

Mind you I think the Arduino example of a multiplexed output driving several LEDs might have had some part in you falling into this trap. I complained about this many years ago, but they said it was just an example to show what could be done. I said that it was knowledge that lead nowhere because it was a technique that could not be extended and should not be done in the first place. My arguments did not convince them and so it remains.

I'm going to re-do my approach to RGB LEDs and MAX7219.
All my thru-hole RGB LEDs that I can find are common anode, vs common cathode.
So the approach would be like this.
Digit0 would turn on the Red LED from LEDs D0 to D7
Digit1 the Green from D0 to D7
Digit2 the Blue from D0 to D7
Digit 3 the Red from D8 to D15
Digit 4 the Green from D8 to D15
Digit 5 the Blue from D8 to D15.

So not quite convenient code-wise as common cathode, where all of One LED is controlled with one digit
but the multiplexing would work out the same, with 6 LEDs on at any one time.

Okay, I have one common anode LED wired up with color controlled by the common cathodes:
Segment A is driving the anode, Digits 1,2,3 are controlling the cathode

#include <SPI.h>
byte ssPin = 10;
byte nodecodeDecodeMode = 0x9;
byte intensityLevel = 0x0A;
byte scanLimit = 0x0B;
byte shutdownNormal = 0x0C;
// 0x0D, 0x0E not used
byte normalDisplayTest = 0x0F;
byte x;
unsigned long delayTime = 500;

void max7219 (byte registerNumber, byte dataToWrite) {
  digitalWrite (ssPin, LOW);
  SPI.transfer (registerNumber);
  digitalWrite (ssPin, HIGH);

  digitalWrite (ssPin, LOW);
  SPI.transfer (dataToWrite);
  digitalWrite (ssPin, HIGH);
}

void setup() {
  Serial.begin(115200);
  pinMode (ssPin, OUTPUT);
  SPI.begin();
  // set up registers
  max7219 (nodecodeDecodeMode, 0x00); // no decode
  max7219 (intensityLevel, 0x07); // mid level
  max7219 (scanLimit, 0x07); // 0,1,2 only
  max7219 (shutdownNormal, 0x01); // not shutdown (normal mode)
  max7219 (normalDisplayTest, 0x00); // not display test (normal operation)
}

void loop() {
  Serial.println ("0,0,0");
  max7219       (1, 0x00); 
  max7219       (2, 0x00); 
  max7219       (3, 0x00); 
  delay (delayTime);
  Serial.println ("00,0,40");
  max7219       (1, 0x00); // color 1 on DP-a-b-c-d-e-f-g D7-D0
  max7219       (2, 0x00); 
  max7219       (3, 0x40); 
  delay (delayTime);
    Serial.println ("0,40,0");
  max7219       (1, 0x00); 
  max7219       (2, 0x40); 
  max7219       (3, 0x00);
  delay (delayTime);
    Serial.println ("00,40,40");
  max7219       (1, 0x00); 
  max7219       (2, 0x40); 
  max7219       (3, 0x40);
  delay (delayTime);
  Serial.println ("40,0,0");
  max7219       (1, 0x40); 
  max7219       (2, 0x00); 
  max7219       (3, 0x00);
  delay (delayTime);
  Serial.println ("40,0,40");
  max7219       (1, 0x40); 
  max7219       (2, 0x00); 
  max7219       (3, 0x40); 
  delay (delayTime);
    Serial.println ("40,40,0");
  max7219       (1, 0x40); 
  max7219       (2, 0x40); 
  max7219       (3, 0x00); 
  delay (delayTime);
    Serial.println ("40,40,40");
  max7219       (1, 0x40); 
  max7219       (2, 0x40); 
  max7219       (3, 0x40); 
  delay (delayTime);
}

hello guys,
this thing is driving me crazy, I've been trying and trying with no luck at all. I am using a 16 channel analog multiplexer (this one 74HC4067), and I have 5 RGB leds connected to it (channel 0,1,2 for the first RGB led, and 3,4,5 for the second RGB led and so on).

I want to light them up at the same time simultaneously. but I've seen that it's kind of not possible (is this true ??), instead I need to put a delay(1), or something really small to make the illusion that they're running at the same time (is this true as well?).

the thing is that the leds are flickering, and I cannot fix this. I added another multiplexer for another 5 RGB leds and they started to flicker even more.

is there a way to light them up with multiplexing but to make them stable at least, or this type of multiplexer is just not suitable for the job (the 74HC4067) I don't get it anymore. some one explain please.

I've attacked a picture of the circuit. and the code is as follows:

#include <Wire.h>

int s3_2 = 10;
int s2_2 = 11;
int s1_2 = 12;
int s0_2 = 13;
int sig_2 = A0;//9;

int s3 = 6;
int s2 = 7;
int s1 = 8;
int s0 = 9;
int sig = A1;//4;
  int muxChannel[16][4]={
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10
    {1,1,0,1}, //channel 11
    {0,0,1,1}, //channel 12
    {1,0,1,1}, //channel 13
    {0,1,1,1}, //channel 14
    {1,1,1,1}  //channel 15
  }; 

  int controlPin[] = {s0, s1, s2, s3};
  int controlPin2[] = {s0_2, s1_2, s2_2, s3_2};

int led1[6] = {0, 1, 2, 0, 255, 0};
int led2[6] = {3, 4, 5, 0, 0, 255};
int led3[6] = {6, 7, 8, 0, 255, 0};
int led4[6] = {9, 10, 11, 0, 255, 0};
int led5[6] = {12, 13, 14, 255,255, 0};

int led6[6] = {0, 1, 2, 0, 255, 0};
int led7[6] = {3, 4, 5, 255, 0, 0};
int led8[6] = {6, 7, 8, 0, 255, 0};
int led9[6] = {9, 10, 11, 0, 255, 255};
int led10[6] = {12, 13, 14, 255, 0, 0};


void setup()
{
 Serial.begin(9600);           /* start serial for debug */
 

  pinMode(s0, OUTPUT);
  pinMode(s1, OUTPUT);
  pinMode(s2, OUTPUT);
  pinMode(s3, OUTPUT);
  pinMode(sig, OUTPUT);
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  
    pinMode(s0_2, OUTPUT);
  pinMode(s1_2, OUTPUT);
  pinMode(s2_2, OUTPUT);
  pinMode(s3_2, OUTPUT);
  pinMode(sig_2, OUTPUT);
  digitalWrite(s0_2, LOW);
  digitalWrite(s1_2, LOW);
  digitalWrite(s2_2, LOW);
  digitalWrite(s3_2, LOW);

  delay(500);
}

void loop()
{
 
    setCol(led1, led1[3], led1[4], led1[5]);
 //delay(1);     
    setCol(led2, led2[3], led2[4], led2[5]); 
//delay(1);
    setCol(led3, led3[3], led3[4], led3[5]);
 //delay(1);
    setCol(led4, led4[3], led4[4], led4[5]);
  //delay(1);
    setCol(led5, led5[3], led5[4], led5[5]);
  //delay(1);  
  
    setCol_row2(led6, led6[3], led6[4], led6[5]);
//delay(1);   
    setCol_row2(led7, led7[3], led7[4], led7[5]);
//delay(1);      
    setCol_row2(led8, led8[3], led8[4], led8[5]);
 // delay(1);
    setCol_row2(led9, led9[3], led9[4], led9[5]);
 // delay(1);      
    setCol_row2(led10, led10[3], led10[4], led10[5]);
  //delay(1);
}

void setCol(int* led, int r, int g, int b) {
    for(int i = 0; i < 4; i ++)
      digitalWrite(controlPin[i], muxChannel[led[0]][i]);
    analogWrite(sig, r);
    delay(1);
    for(int i = 0; i < 4; i ++)
      digitalWrite(controlPin[i], muxChannel[led[1]][i]);
    analogWrite(sig, g);
    delay(1);
    for(int i = 0; i < 4; i ++)
      digitalWrite(controlPin[i], muxChannel[led[2]][i]);
    analogWrite(sig, b);
    delay(1);
}
void setCol_row2(int* led, int r, int g, int b) {
    for(int i = 0; i < 4; i ++)
      digitalWrite(controlPin2[i], muxChannel[led[0]][i]);
    analogWrite(sig_2, r);
    delay(1);
    for(int i = 0; i < 4; i ++)
      digitalWrite(controlPin2[i], muxChannel[led[1]][i]);
    analogWrite(sig_2, g);
    delay(1);
    for(int i = 0; i < 4; i ++)
      digitalWrite(controlPin2[i], muxChannel[led[2]][i]);
    analogWrite(sig_2, b);
    delay(1);
}

Basically you bought the wrong device; there are boards with 16 PWM outputs (e.g. Adafruit 16-Channel 12-bit PWM/Servo Shield - I2C interface : ID 1411 : $17.50 : Adafruit Industries, Unique & fun DIY electronics and kits based on the PCA9685).

The 4067 can only control one led at a time, at the moment that you switch to the next led, the previous one will be off.

What you want to achieve with a 4067 is known as persistance of view. Switching fast enough and it will look like they are all on.

You can try to use delayMicroseconds. Further digitalWrite (to select the channel) is relatively slow; try direct port manipulation; note that you will need to consult the datasheet of the Mega to find the correct ports.

sterretje:
Basically you bought the wrong device; there are boards with 16 PWM outputs (e.g. Adafruit 16-Channel 12-bit PWM/Servo Shield - I2C interface : ID 1411 : $17.50 : Adafruit Industries, Unique & fun DIY electronics and kits based on the PCA9685).

The 4067 can only control one led at a time, at the moment that you switch to the next led, the previous one will be off.

What you want to achieve with a 4067 is known as persistance of view. Switching fast enough and it will look like they are all on.

You can try to use delayMicroseconds. Further digitalWrite (to select the channel) is relatively slow; try direct port manipulation; note that you will need to consult the datasheet of the Mega to find the correct ports.

did it with delayMicroseconds and it worked, but may you please explain what did you mean with the digitalWrite? I didn't quite get that.

Also, did you mean by 16 PWM outputs, that there are multiplexers with 16 outputs instead of 1 (sig) ?

Thank you :smiley:

Basically lighting LEDs with a multiplexer is an incredibly stupid idea. You have all the disadvantages of multiplexing but with none of the advantages.

Yes there is an example to do this on the official Arduino site and it leads people astray into thinking it is a thing.

haytam111:
but may you please explain what did you mean with the digitalWrite? I didn't quite get that.

digitalWrite() does a lot under the hood that is not necessary if you stick to one processor (in your case the Mega). So if you want to speed up the process, you can directly modify the pins (and you can modify one port (8 pins) at a time in one go); so in your case, instead of 4 digitalWrites, you can use a single instruction (probably one CPU cycle, not checked) to set 4 digital pins.

Disadvantage is that if you ever want to use it on e.g. an Uno, you will have to rework the code.

haytam111:
Also, did you mean by 16 PWM outputs, that there are multiplexers with 16 outputs instead of 1 (sig) ?

The board that I mentioned is not a multiplexer. From a PWM perspective, you can compare it with a Mega; the Mega has 15 PWM capable outputs, the board I mentioned has 16.

I thought that I asked, but can't find it back: why don't you use the PWM outputs of the Mega?

Basically you bought the wrong device; there are boards with 16 PWM outputs (e.g. Adafruit 16-Channel 12-bit PWM/Servo Shield - I2C interface : ID 1411 : $17.50 : Adafruit Industries, Unique & fun DIY electronics and kits based on the PCA9685).

I have the same idea, why not use a proper LED driver IC. Beside the PCA9685, I can recommend the SX1509

And as others have already told, there a lot of PWM pins on a Mega
2 - 13, 44 - 46

  • two pins with softPWM could solve your problem also?

Surprised no-one has (or did I miss it?) mentioned how much more sensible it would be to use WS2812/ "NeoPixel" LEDs?