Hi there,
I've just spent a couple of weeks tinkering with software PWM, for RGB leds AND rotary encoders
Co-incidence eh?
Well, I've done a few software PWM algorithms. The two I feel are probably the most useful are:
1. Using CCP1 (one hardware module) and TMR1 in 'compare mode'. Put your PWM values in order of value, then, load in the first to tmr1, resest it, and wait for it to interupt. Also turn on all LED's (just to start with). When it interupts, turn the pin off for that particular PWM (led) and load in the next value. Do this for the final one, and at the end load in '255'. This will give you 3 channel 8-bit PWM, pretty fast (I got >1Khz on a 4Mhz 628A PIC). Plus the interupt is only called 4 times per PWM period, its 20 lines max giving 80 instructions per PWM period. There is one problem though. This pushes all of the complexity into 'setting up' the registers for it. Once the PWM is running, as long as the values aren't changed it uses about 0.6% of the PICs time generating the PWM. Also, its tricky to get full resolution (PWM = 0, means the LED is OFF, and 255 means its ON all the time). I'm not sure whether to post the code because it is still in the testing stages, plus, for your app, I don't think it would be useful, especially if you are planning on changing the PWM values regularly. As far as I know, few others have done this, because its only for certain apps (useless in others) but it IS very efficient, just horrendously complicated.
2. The simplest (and probably most inefficient method) is to just have a small routine that constantly decrements a counter, and decrements temp PWM values. When a PWM value reaches 0, its pin is cleared. When the counter rolls over, it is reloaded, and all the pins are turned on. The problem here is that the counter counts at 2 to the power of the resolution. Eg: 8-bit PWM, 256 (including 0), 5-bit PWM 32.
Some code:
clrW ; clear the working reg
dec PWMR ; dec RED skip on 0
iorlw b'10000000'
dec PWMG ; dec GREEN skip on 0
iorlw b'01000000'
dec PWMR ; dec BLUE on 0
iorlw b'00100000'
dec Counter ; dec skip on 0
goto $ + 3
reload Counter, PWMR-PWMB
movlw b'11100000'
movwf PORTB ; moves a pin pattern to PORTB, so if green and red are 0, it gives '0010000', if counter rolled over,it was reloaded and '1110000' is dumped in PORTB.
For 8-bit PWM...the routine would have to run 256 times per PWM period. I think I got mine down to 16 instructons, including reload. Thats 256*16 per PWM period. = 4096. On a 20Mhz PIC that gives a max frquency of over 1Khz, (244Hz with 4Mhz) but does not give you time to do anything else.
You could run the above method with a timer interupt. But, because you are limited in prescalers, you can only call the routine every 16, 32, 64, 128 Fosc's etc.. With 20Mhz osc, you shouldn't notice any flickering though. Just make sure you don't call it again while you're still running it (turn off interupts in ISR). Also, in the routine, you could just load in (255-delay) to TMR0, that way, you can call the routine every 16-256 clocks.
One idea that I used to read 3 pots to control an RGB LED (from 0-100%) is simply to use the aobve routine but add a routine after it that reads the pots.
In your case you would have a 'read encoder' routine. So you go through your PWM routine, then read the encoder, change any values if needed, then back to the PWM routine in one big loop. This does mean however, that you'll be checking your encoder 256 times per PWM period (VERY often). Some simple loops and counters would mean you could only check the encoder every 10 or 50 PWM periods, so when its not checking, the PWM is running at its full speed.
It doesn't leave much room for adding anything else, but it will do the job quite nicely. Experiement with resolutions, I prefer 8-bit, but 6-bit PWM is fine for fading. When you get to 5-bit or below and you 'fade' the leds, you notice sudden jumps in the brightness as opposed to a smooth transistion.
Have you googled 'software PWM PIC' ? There was something on PIClist a while back which did the same thing.
Sorry for the long post, it was rushed, its late. Good luck.
Blueteeth.