Blinking LEDs, what can be easier, right? For a recent project I needed to multiplex 2 sets of 6 LED each.
The circuit schematic has the LEDs driven by 6 pins on an Arduino plus two pins to activate one bank or the other. LEDs are these ones from LCSC.
My Arduino code lights up each bank of LEDs for around 1ms with its corresponding pattern. My test pattern consisted of turning on just LED7 for one second and then turning on LED6 for one second.
The Arduino code loops every millisecond and goes through the following:
- Turn off both banks
- Wait for transistors to fully switch off
- Place voltage on pins corresponding to LEDs that should turn on
- Turn on current bank
uint8_t mask[2] = {0b000000, 0b000001};
void setup()
{
// Banks, through transistors
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
// LEDs, through resistors
pinMode(A0, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
}
// Loop runs every millisecond or so because of the delay(1) near the end
void loop()
{
static uint8_t pattern = 0;
static uint32_t lastChangeTimestamp = 0;
// Turn off both banks
digitalWrite(2, LOW);
digitalWrite(3, LOW);
// Wait for transistor to fully switch off. This is not really
// necessary when using digitalWrite() as this function is sooo slow
// but would be required if we addressed ports directly
delay(0.050);
// turn off all LEDs
digitalWrite(A0, LOW);
digitalWrite(A1, LOW);
digitalWrite(A2, LOW);
digitalWrite(A3, LOW);
digitalWrite(A4, LOW);
digitalWrite(A5, LOW);
// Turn on required LEDs
if (mask[pattern] & 0x01) digitalWrite(A0, HIGH);
if (mask[pattern] & 0x02) digitalWrite(A1, HIGH);
if (mask[pattern] & 0x04) digitalWrite(A2, HIGH);
if (mask[pattern] & 0x08) digitalWrite(A3, HIGH);
if (mask[pattern] & 0x10) digitalWrite(A4, HIGH);
if (mask[pattern] & 0x20) digitalWrite(A5, HIGH);
// Activate required bank
if (pattern == 0) digitalWrite(2, HIGH);
else digitalWrite(3, HIGH);
// toggle pattern
pattern ^= 1;
delay(1);
// Every second switch the displayed pattern
if (millis() - lastChangeTimestamp > 1000)
{
if (mask[1] == 1)
{
mask[1] = 0;
mask[0] = 32;
}
else
{
mask[1] = 1;
mask[0] = 0;
}
lastChangeTimestamp = millis();
}
}
Ghosting
This sounded simple enough. But when tried out on a breadboard, in addition to the LED that I expected to have turned on I also had the corresponding LED dimly lit in the OTHER bank. That is, while I wanted LED7 and LED6 to alternate every second, I got LED7 bright and LED1 dim for one second, then LED6 bright and LED12 dim.
It's faint but enough to bug me.
Debugging
As stuff is happening every 1ms, first thing I did was slow it down. I went down to 1 second between changing banks to see exactly when the ghosting occurs. The unexpected LED gave a very brief flash whenever voltage was placed on the OTHER bank's LEDs (the bank with the legitimate LEDs). For example, when LED7 should turn on, LED1 also flashes briefly
The timing diagram shows the transition from displaying LED1..LED6 (active with the transistor fed by the D2 line) to displaying LED7..LED12. After turning off both banks there is a delay to account for the transistor switch-off time and then all LEDs are switched off. Everything was already off so nothing changed here. Then line A0 goes high because in the next bank LED7 should be on. At this moment LED1 flashes briefly. Afterwards the bank containing LED7 is turned on by bringing line D3 high.
Simplifying the schematic just to the minimum number of components we need we can look at the steps the circuit goes through.
Only when A0 goes high LED1 flashes briefly. Were the transistor leaky, LED1 would stay dimly lit, not just flash. So it looks like a capacitor is charging. This suggests that LED2 behaves like a capacitor and a little bit of current goes through it until it charges.
LED capacitance
Diodes...
Read more »
Why not turn on the tranny first, then the address?
Also, your 1st video shows the dim LED on the whole time (even while camera is moving over time, is the tranny really off, or your video is not really correct? If it is bleeding I have one solution.