Charlieplexing: LEDs have different brightness

  • Thread starter bremenfallturm
  • Start date
  • Tags
    Leds Timer
  • #1
bremenfallturm
71
11
TL;DR Summary
I have made a basic code to Charlieplex a bunch of LEDs. I have the problem that the last LED I am trying to turn on in the circuit appears much brighter than the others. Why?
Hi!

I am questioning my design choices, but I will try to push this circuit a little more until I get a microcontroller with more pins and don't use Charlieplexing.

Charlieplexing is a method of controlling n*(n-1), in this case LEDs, using n GPIO pins. This is achieved by alternating the state of pins: high, low, or input.

What I want to do:
I am trying to create a countdown timer circuit. The timer is going to light up between 1 and 12 LEDs, acting like a progressbar to show the time left. Also, the last LED will blink every second, so the progress bar indicates that the timer is counting down.

See the picture above for what I am trying to build:
ezgif.com-animated-gif-maker(2).gif

So my requirements are:
* Must be able to address/control all 12 LEDs individually (sometimes I might need to turn on one of them, sometimes two, sometimes all, and so on).
* The rightmost LED of the lit-up LEDs must blink, like in the picture above.

I tried to use Charlieplexing (explained above) so I could get away with a microcontroller with few pins.
My problem:
I built a standard Charlieplexing circuit to control 12 LEDs (see for example: http://www.multiwingspan.co.uk/arduino.php?page=charlie) on a breadboard.
To get LEDs lit up at the same time, I use a very small delay between when each pin is updated.
I get all the LEDs to appear lit up simultaneously, however, the LED that is supposed to blink (see the image above) somehow appears brighter than the other LEDs.
This is the code that I run on an Arduino UNO (the Charliplexing pins used are 13,12,11 and 10):
C++:
/* charlieplexing_12_pins.ino
Test Arduino sketch (to run on an Arduino UNO, not Attinys)
for testing 12-pin Charlieplexing.
*/
 const char allPinStates[12][4] = {
   {
     1,
     0,
     -1,
     -1
   }, // LED 1
   {
     0,
     1,
     -1,
     -1
   }, // LED 2
   {
     1,
     -1,
     0,
     -1
   }, // LED 3
   {
     0,
     -1,
     1,
     -1
   }, // LED 4
   {
     1,
     -1,
     -1,
     0
   }, // LED 5
   {
     0,
     -1,
     -1,
     1
   }, // LED 6
   {
     -1,
     1,
     0,
     -1
   }, // LED 7
   {
     -1,
     0,
     1,
     -1
   }, // LED 8
   {
     -1,
     1,
     -1,
     0
   }, // LED 9
   {
     -1,
     0,
     -1,
     1
   }, // LED 10
   {
     -1,
     -1,
     1,
     0
   }, // LED 11
   {
     -1,
     -1,
     0,
     1
   } // LED 12
 };
 const char gpioPins[4] = {
   13,
   12,
   11,
   10
 };
 // Used to set the 4 used pins to their wanted state
 // pinStates is a pointer to a const char[] with 4 entries,
 // each entry indicating the state of each GPIO pin:
 // 1: Pin should be OUTPUT+ON
 // 0: Pin should be OFF+OFF
 // -1: Pin should be input
 void setPinState(const char* pinStates){
   for (int j = 0; j < 4; j++) {
       const char pinState = * (pinStates + j);
       const char gpioPin = gpioPins[j];
       if (pinState != -1) {
         pinMode(gpioPin, OUTPUT);
         digitalWrite(gpioPin, pinState);
       } else {
         pinMode(gpioPin, INPUT);
       }
     }
 }
 // Later intended to be used as a progress bar for the timer,
 // to indicate time left, by only having turned on for example LED 1,2,3, and 4.
 char numberOfLEDsOn = 8;
 // Used to blink the rightmost LED on the progressbar every second,
 // keeping all other LEDs before it on, to indicate that the timer
 // is counting down.
 short timeElapsed = 0;
 char blinkState = 0;
 void setup() {

 }
 void loop() {
   // Turn on all LEDs up until the LED to blink (see comments around "timeElapsed") above
   for (int i = 0; i < numberOfLEDsOn-1; i++) {
     // For each pin state, set the LEDs accordingly
     setPinState(allPinStates[i]);
  }
  // Blink last LED in progressbar every second. See comments around "timeElapsed") above.
  if (blinkState){
    setPinState(allPinStates[numberOfLEDsOn-1]);
  }
  delay(1);
  timeElapsed++;
  // Update blinkState every second
  if (timeElapsed >= 1000){
    timeElapsed = 0;
    blinkState = !blinkState;
  }
 }




In the video below, I run the code above, which is expected to be turn on 8 of the 12 LEDs and the uneven brightness issue can be illustrated. Watch the video and you can see that these LEDs (LED 7 and 8) are always brighter than the rest:
1738089730324.png





(the breadboard connection won't win awards, I know...)

I did not connect the LEDs on my breadboard circuit in a logical order - hope you can bear with that. The 8th LED is supposed to alternate between on and off like in the image I provided above.


My setup gives me uneven brightness on just the last LED I want to illuminate. Why? Is it a timing problem with my code? Circuit issue? Charlieplexing limitation?

Many thanks for your help!

Some complementary information:
The LEDs are all identical. They are rated: Red at 20 mA: 1,92-2,06 V. I run them on an Arduino UNO with 150ohm resistors between each pin and the rest of the connections that the pin has.
 

Attachments

  • 1738089687563.png
    1738089687563.png
    64.9 KB · Views: 4
Engineering news on Phys.org
  • #2
No schematic? OK, then, I don't know. Partly because I don't want to take the time to read your code.

First step: separate HW vs. SW issues by swapping, with as little disturbance as possible, the I/O port HW connections. For example, what if one of your 150Ω resistors was really 100Ω? No amount of looking at your code will spot that.

You might do similar swapping in your code to distinguish between port HW or initialization differences and your high level code.
 
Last edited:
  • Like
Likes sophiecentaur
  • #3
Yeah without a schematic you will get no help. I've done something similar to this successfully. I wired LEDs in pairs back to back. It's been a while. Arranged in a matrix. I will not debug your code either. Just make sure you spend equal time everywhere. Don't be looping through and have a branch or interrupt someplace that causes the program to spend more time with a certain port or pair of ports where they are not set so that the LEDs are off. I recall fumbling a bit to get it to work. I can see how someone could overlook something.
 
  • #4
Plus some very general circuit troubleshooting advice:

Don't assume that you know where the problem is or is likely to be. Don't assume that thinking harder about the thing you were just thinking about will help much. Be systematic and break the problem down into separate functional pieces. Then go through a set of simple tests to verify that each piece is working properly. Knowing what isn't the problem is the path to simplification of your problem. Step 1 is to find the problem, step 2 is to find out why, step 3 is to fix it.

This sounds like a lot of work, but it can go pretty quickly. Very often (very, very, very, often) the problem is that you are assuming something that just isn't true. Question your basic assumptions and do systematic analysis. For example, what if the LED is mislabeled? All you can do is prove that it's different, you may never know why. What if the uC I/O ports aren't all the same? Reread that datasheet again, for like the 17th time. What if your wires aren't connected the way you think they are?
 
  • Like
Likes Averagesupernova
  • #5
"Charlieplex" is a new one on me, could you describe it?

My first thought is that the first 11 LEDs may be switching On & Off at a rapid rate, thus appearing dimmer due to less than 100% duty cycle.

Then if the #12 LED is full on for a second, it will appear brighter than the rest of them.

Cheers,
Tom
 
  • #6
Tom.G said:
"Charlieplex" is a new one on me, could you describe it?

My first thought is that the first 11 LEDs may be switching On & Off at a rapid rate, thus appearing dimmer due to less than 100% duty cycle.

Then if the #12 LED is full on for a second, it will appear brighter than the rest of them.

Cheers,
Tom
Or google search. That works too.
https://en.wikipedia.org/wiki/Charlieplexing
 
  • Like
Likes Tom.G
  • #7
Flashing lights look brighter than steady ones, hence their use on bicycles.
 
  • #8
DaveE said:
No schematic? OK, then, I don't know. Partly because I don't want to take the time to read your code.

First step separate HW vs. SW issues by swapping, with as little disturbance as possible, the I/O port HW connections. For example, what if one of your 150Ω resistors was really 100Ω? No amount of looking at your code will spot that.

You might do similar swapping in your code to distinguish between port HW or initialization differences and your high level code.
The photo of the setup implies swapping a diode and resistor would be only a five minute job. I guess the OP is happier with SW than HW.
 
  • #9
This is a software problem. Think about how much time there is between setPinState(allPinStates[0]); and setPinState(allPinStates[1]); and then think about the state of the pins during the delay(1);.
 
  • #10
Also note that running a loop 1000 times with delay(1) in it does not give you a timer that updates once a second.
 
  • #11
pbuk said:
This is a software problem.
A scope would reveal if there is a timing problem. It may be easier to 'PRINT TIME' commands to a file. That would reveal unequal steps. Many ways of killing a cat.
 
Back
Top