I am trying to drive 8 LEDs connected to a 74HC595
shift register with PWM. I want to be able to set each LED to a different brightness. The PWM signal is connected to the Enable Output
pin of the shift register (it is low active so the PWM signal must be inverted). By selecting each LED (only one LED at a time) and setting the PWM frequency I thought it would have been done. So currently I have following approach:
- set PWM frequency
- "activate" desired LED by writing according value to shift register (for example first LED would be
0b00000001
- write shift register value to shift register outputs by setting the
Latch
input to1
and clear it back to0
- start over again with new PWM frequency and next LED
This is resulting in following fault: When I set the first LED to full brightness and the next LED to no brightness (off) I notice that for a short time the full brightness of the first LED is showing up on the next LED. This behavior gives the second LED a little brightness which is bad because I want no brightness (turn it off). I know I could just jump over the LED to leave it off but I would like to only control LEDs brightness by setting the PWM frequency. Also I have this effect when setting for example first LED to full brightness and next LED to half brightness. There is always the brightness of the preceding LED on the next LED for a short time.
I think it is because I can't control the PWM output like I can control the shift register output by its latch. The PWM frequency is applied as soon as I set it in my code. This causes the short blink with preceding LED's brightness. I also tried to change the order of steps in my approach.
Do you have any idea how to solve this problem?
Some lines of my real code (if the pseudo code is not enough):
OCR0A = 0; // set PWM to full brightness
SPDR = 0b00000001; // select first LED
while(!(SPSR & (1<<SPIF))); // write to shift register
PORTB = 0; // latch outputs
PORTB = 1;
_delay_ms(1);
OCR0A = 255; // set PWM to no brightness (off)
SPDR = 0b00000010; // select second LED
while(!(SPSR & (1<<SPIF)));
PORTB = 0;
PORTB = 1;
_delay_ms(1);
My target hardware is an ATmega168
clocked at 20 MHz. I am using avr-gcc
.