Go Down

Topic: Need more control over PWM for led fade. (Read 10583 times) previous topic - next topic

tylernt

#30
Nov 12, 2013, 09:08 pm Last Edit: Nov 12, 2013, 09:14 pm by tylernt Reason: 1
How about this.

Use normal PWM for 1-100%. For 0-1%, switch to software PWM. And by software, I mean fire a routine like this:

{
Turn the LED on
Burn in a short empty loop similar to for(byte i=0; i < duration; i++); // <-- note semicolon
Turn the LED off
}

'duration' can be between 0 and some small value (maybe 255?) to control the duty cycle in fine steps. You'll have to find the point where a large enough 'duration' gives the same brightness as a low hardware PWM value.

You can use micros() (Blink Without Delay style) to decide when to fire the software PWM routine for each LED. Firing each of 3 LED colors every 1,000 micros or so should be flicker free I would think.

digitalWriteFast2() might also be an appropriate library to use.

EDIT: I think this is kind of what you are already doing, albeit at a millisecond time scale instead of microsecond. So if it works, great! If it's flickery, go down into microsecond timescales.

Paul__B

I was suggesting much the same, except that you could probably use hardware PWM in short bursts defined by a software loop.

nickgammon

#32
Nov 13, 2013, 09:03 pm Last Edit: Nov 13, 2013, 09:05 pm by Nick Gammon Reason: 1
With 16-bit PWM output you can get pretty smooth steps. Example code using Timer 1:

Code: [Select]

const byte LED = 10;  // Timer 1 "B" output: OC1B

void setup()
{
 pinMode (LED, OUTPUT);
 TCCR1A = bit (WGM10) | bit (WGM11) | bit (COM1B1); // fast PWM, clear OC1B on compare
 TCCR1B = bit (WGM12) | bit (WGM13) | bit (CS10);   // fast PWM, no prescaler
 OCR1A =  65000;          
 }  // end of setup

void loop()
 {
 OCR1B = analogRead (0);
 }


Hook up a pot to A0 (and 5v/Gnd) and put a LED on pin 10. The code only shows the "lower end" of the range (ie. 0 to 1023 out of 65000) so the LED won't get very bright, but it shows the gradual dimming at the low end.

With 65000 discrete steps the difference between the low ones is quite smooth. Unfortunately you only have one 16-bit timer. If all the three colours are going to fade together you might be able to use one pin for the brightness and other ones for the colour levels. Or get another couple of chips. At least this demonstrates what you can expect from 16-bit PWM.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

tylernt

Unfortunately you only have one 16-bit timer.
Yeah, that makes it hard to do three (red, green, blue). There are ways of multiplexing multiple things onto one timer (http://forum.arduino.cc/index.php?topic=198337.0) but my math-fu is too weak to decide if multiplexing reduces the available bit-resolution.

Even if if it doesn't, at certain points you'll want to toggle one LED and toggle the next LED on really close in time to each other, but the interrupt latency means one will happen a bit later than expected. This will lead to jitter -- a slightly brighter or dimmer LED than expected -- but this may or may not be noticeable to the human eye. And you may be able to avoid it by dynamically rescheduling the pulse cycle to avoid event collisions.

Go Up