I understand what forum member MBedder is trying to say unfortunately his example is flawed. If he had used decfsnz instructions in his example then LEDs with duty cycle settings of 0 would be lighted continuously. There are also better soft PWM "counter method" algorithms that don't require extra processing "overhead" at end-of-period and don't require nearly so many variables.
Here's a somewhat more efficient soft PWM "counter method" ISR driver example for 16-bit core devices;
;
; soft PWM "counter method", 8 bits, 256 levels, 16 bit core
;
; void tmr2_isr()
; { pir1.CCP1IF = 0; //
; if(dcy >= Led[0]) shadow.0 = 0; //
; if(dcy >= Led[1]) shadow.1 = 0; //
; if(dcy >= Led[2]) shadow.2 = 0; //
; if(dcy >= Led[3]) shadow.3 = 0; //
; if(dcy >= Led[4]) shadow.4 = 0; //
; if(dcy >= Led[5]) shadow.5 = 0; //
; if(dcy >= Led[6]) shadow.6 = 0; //
; if(dcy >= Led[7]) shadow.7 = 0; //
; latb = shadow; //
; dcy++ // inc duty cycle, 0..255
; if(dcy == 0) // if end-of-period
; shadow = 255; //
; }
;
; 23 words, 26 cycles (isochronous), 10 bytes RAM
;
bcf PIR1,TMR2IF ; clear timer 2 interrupt flag
movf dcy,W ; duty cycle counter, 0..255
cpfsgt Led+0 ;
bcf Shadow,0 ;
cpfsgt Led+1 ;
bcf Shadow,1 ;
cpfsgt Led+2 ;
bcf Shadow,2 ;
cpfsgt Led+3 ;
bcf Shadow,3 ;
cpfsgt Led+4 ;
bcf Shadow,4 ;
cpfsgt Led+5 ;
bcf Shadow,5 ;
cpfsgt Led+6 ;
bcf Shadow,6 ;
cpfsgt Led+7 ;
bcf Shadow,8 ;
movff Shadow,LATB ;
infsnz dcy,F ; end-of-period? no, skip, else
setf Shadow ; reset shadow
retfie FAST ;
And here's a relatively efficient soft PWM "counter method" ISR driver example for 14-bit core devices;
;
; soft PWM "counter method", 8 bits, 256 levels, 14 bit core
;
org 0x0004
radix dec
isr
movwf w_isr ; save WREG |B?
swapf STATUS,W ; don't change STATUS bits |B?
movwf s_isr ; save STATUS |B?
clrf STATUS ; bank 0 |B0
movf PCLATH,W ; |B0
movwf p_isr ; save PCLATH |B0
clrf PCLATH ; page 0 |B0
bcf PIR1,TMR2IF ; clear timer 2 interrupt flag |B0
;
; do 1/256th step, 26 cycles (isochronous)
;
movf led+0,W ; led0 pwm value, 0..255 |B0
subwf dcy,W ; C = led0 => dcy |B0
rrf shadow,F ; |B0
movf led+1,W ; led1 pwm value, 0..255 |B0
subwf dcy,W ; C = led1 => dcy |B0
rrf shadow,F ; |B0
movf led+2,W ; led2 pwm value, 0..255 |B0
subwf dcy,W ; C = led2 => dcy |B0
rrf shadow,F ; |B0
movf led+3,W ; led3 pwm value, 0..255 |B0
subwf dcy,W ; C = led3 => dcy |B0
rrf shadow,F ; |B0
movf led+4,W ; led4 pwm value, 0..255 |B0
subwf dcy,W ; C = led4 => dcy |B0
rrf shadow,F ; |B0
movf led+5,W ; led5 pwm value, 0..255 |B0
subwf dcy,W ; C = led5 => dcy |B0
rrf shadow,F ; |B0
movf led+6,W ; led6 pwm value, 0..255 |B0
subwf dcy,W ; C = led6 => dcy |B0
rrf shadow,F ; |B0
movf led+7,W ; led7 pwm value, 0..255 |B0
subwf dcy,W ; C = led7 => dcy |B0
rrf shadow,W ; W = led 'step' output |B0
; xorlw 0xFF ; for active hi outputs |B0
movwf PORTB ; update LEDs |B0
incf dcy,F ; dcy++, 0..255 |B0
;
; restore context, 8 cycles (isochronous)
;
movf p_isr,W ; |B0
movwf PCLATH ; restore PCLATH |B0
swapf s_isr,W ; |B0
movwf STATUS ; restore STATUS |B?
swapf w_isr,f ; don't screw up STATUS |B?
swapf w_isr,W ; restore WREG |B?
retfie ; return from interrupt |B?
post edited by K8LH - 2009/04/26 08:10:34