;******************************************************************
;
; // setup a 1000 usec PWM period with PR2 = 249 and prescaler
; // 16:1 (16 MHz clock) for 20 PWM 'frames' per 20 msec Servo
; // period and 1 usec pulse width resolution
;
; int servo = 1500; // 0..20000 in 1 usec 'ticks'
; int width = 0; // ISR work variable
; int frame = 1; // frame number 1..20
;
; void ISR()
; { PIR1bits.TMR2IF = 0; // clear Timer 2 interrupt flag
; if (--frame == 0) // if end of the 20 msec period
; { frame = 20; // reset for new 20 msec period
; width = servo; // reset 'width' work variable
; }
; if ((width > 1000) // if width > 1000 usecs
; { CCPR1L = 250; // do a 100% duty cycle frame
; CCP1CONbits.CCP1Y = 0; //
; CCP1CONbits.CCP1X = 0; //
; width -= 1000; // subtract 1000 usecs
; }
; else
; { CCP1CONbits.CCP1Y = (width & 1);
; CCP1CONbits.CCP1X = (width & 2);
; CCPR1L = (width >> 2); // 0..249 (0..999 usecs)
; width = 0; // force remaining frames to 0%
; }
; }
;
ISR_vect
;
; save main program context
;
movwf W_ISR ; save W-reg |B?
swapf STATUS,W ; doesn't change STATUS bits |B?
movwf S_ISR ; save STATUS reg |B?
clrf STATUS ; force bank 0 |B0
;
bcf PIR1,TMR2IF ; clear Timer 2 interrupt flag |B0
;
; check for start of new 20 msec servo period
;
decfsz frame,F ; end of 20 msec period? |B0
goto doframex ; no, branch, else |B0
movlw d'20' ; reset pwm frame number |B0
movwf frame ; |B0
movf servo,W ; setup 'pulse' work variable |B0
movwf width ; for new 20 msec servo period |B0
movf servo+1,W ; |B0
movwf width+1 ; |B0
doframex
movlw low(1000) ; width = width - 1000 |B0
subwf width,F ; |B0
movlw high(1000) ; |B0
skpc ; |B0
movlw high(1001) ; |B0
subwf width+1,F ; |B0
movlw d'250' ; assume 100% duty cycle frame |B0
bcf CCP1CON,CCP1Y ; |B0
bcf CCP1CON,CCP1X ; |B0
bc setdutyx ; borrow? no, branch, else |B0
movlw low(1000) ; |B0
addwf width,F ; |B0
movlw high(1000) ; |B0
skpnc ; |B0
movlw high(1001) ; |B0
addwf width+1,F ; |B0
btfsc width,1 ; |B0
bsf CCP1CON,CCP1X ; |B0
btfsc width,0 ; |B0
bsf CCP1CON,CCP1Y ; |B0
rrf width+1,F ; |B0
rrf width,F ; |B0
rrf width+1,F ; |B0
rrf width,W ; W = 0..250 |B0
clrf width ; force 0% duty cycle for the |B0
clrf width+1 ; remaining pwm frames |B0
setdutyx
movwf CCPR1L ; set duty cycle for next frame |B0
;
; restore main program context
;
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 W-reg |B?
retfie ; return from interrupt |B?