I have a very simple PCB that uses 3 GPIO on a ATtiny85 to control 6 LEDs using charlieplexing.
When I try to program certain patterns of lit LEDs (pseudo PWM) I get some LEDs lighting dimly when they should be fully off.
Example where only top or bottom three LEDs should be on alternately:
You can see that LEDs 2 and 5 are dimly glowing rather than being fully off.
I do not have problems when lighting the LEDs one at a time in sequence.
I do not have problems lighting odd and even LEDs alternately.
The schematic is:
The buttons are used to change up and down through 6 modes of operation. Mode 0 lights the LEDs one at a time in sequence. Mode 1 alternates the odd and even LEDs. Mode 2 lights upper or lower three LEDs alternately (and has ghosting problem), the other modes just steadily illuminate the corresponding LED.
The code is split into several files:
main.ino:
Button leftButton = Button(3);
Button rightButton = Button(4);
Sequencer sequencer = Sequencer(200); // ms per step
Alternator alternator = Alternator(0b00101010, 0b00010101);
void setup() {
pinMode(0, OUTPUT);
pinMode(1, OUTPUT);
pinMode(2, OUTPUT);
}
// ------------------------------------------------------------------
const int maxMode = 5;
int mode = 0;
void loop() {
if (leftButton.wasPressed()) {
if (++mode > maxMode) { mode = 0; }
initMode(mode);
}
if (rightButton.wasPressed()) {
if (--mode < 0) { mode = maxMode; }
initMode(mode);
}
switch(mode) {
case (0): sequencer.check(); break;
case (1):
case (2): alternator.check(); break;
default: lightLED(mode); break;
}
}
// ------------------------------------------------------------------
void initMode(int mode) {
switch (mode) {
case (0): sequencer.reset(); break;
case (1): alternator = Alternator(0b00101010, 0b00010101); break;
case (2): alternator = Alternator(0b00111000, 0b00000111); break;
}
}
Alternator.ino
class Alternator {
private:
unsigned long whenChanged = 0;
int interval = 500; // ms
byte pattern, pattern1, pattern2; // bitmap
int count = 0;
public:
Alternator(byte pattern1, byte pattern2) {
this->pattern1 = pattern1;
this->pattern2 = pattern2;
}
void check() {
if ((millis() - whenChanged) > interval) {
if (pattern == pattern1) { pattern = pattern2; }
else { pattern = pattern1; }
whenChanged = millis();
}
if (++count > 5) { count = 0; }
if (((pattern >> count) & 1) == 1) {
lightLED(count);
}
}
};
Sequence.ino
class Sequencer {
private:
int seq; // LED# 0-5
unsigned long whenLastStep; // ms
int stepTime; // ms
const int aDay = 24 * 3600 * 1000; // ms
public:
Sequencer(int stepTime) {
if (stepTime < 1) { stepTime = 1; }
if (stepTime > aDay) { stepTime = aDay; }
this->stepTime = stepTime;
this->seq = 0;
this->whenLastStep = 0;
}
void check() {
if ((millis() - whenLastStep) > stepTime) {
lightLED(seq++);
if (seq > 5) { seq = 0; }
whenLastStep = millis();
}
}
void reset() {
this->seq = 0;
}
};
Charlieplex.ino
const int highs[6] = {0,1,2,1,2,0}; // GPIOs for LEDs 0-5
const int lows[6] = {1,0,1,2,0,2};
// Manipulates 3 GPIO outputs to light one of 6 LEDs.
void lightLED(int i) {
int h, l; // pin to set high, low
if (i < 0 || i >= 6) {
h = 99; l = 99; // all LEDS off
} else {
h = highs[i];
l = lows[i];
}
for (int j=0; j<=2; j++) {
if (j==h || j==l) {
pinMode(j, OUTPUT);
if (j==h) {
digitalWrite(h, HIGH);
} else {
digitalWrite(l, LOW);
}
} else {
pinMode(j, INPUT); // tri-state
}
}
}
Buttons.ino
class Button {
private:
int pin;
const int DebounceDelay = 100; // milliseconds
int lastState = HIGH; // Previous status of button
unsigned long whenLastPressed = 0; // Last time button was pressed
public:
Button(int pin) {
this->pin = pin;
pinMode(pin, INPUT_PULLUP);
}
// Was there an up (HIGH) to down (LOW) transition since last call, and still held down?
bool wasPressed() {
bool result = false;
if ((millis() - whenLastPressed) > DebounceDelay) {
int state = digitalRead(pin);
if ((state == LOW) && (lastState == HIGH)) {
result = true;
whenLastPressed = millis();
}
lastState = state;
}
return result;
}
};
I'm not sure where I am going wrong, any ideas?

