Edit**** The following is my trials and tribulations of getting PWM to work properly on a 12F683. All of the problems were caused by one incorrect instruction in my program, finally found by Pommie, - I typed movf rather than movwf. I am correcting this first post so that anyone reading this thread can get the information they need up front. I am also revising my method for figuring out the values to set up PWM slightly for clarity. My original post was correct, but misleading and incomplete. So....
My understanding of PWM period and duty cycle are:
PERIOD is the number of instructions cycles you want it to take for one cycle of the output, on then off.
PULSE is the number of instructions cycles for the on portion of the cycle.
You put the (PERIOD - 1) into PR2.
You put the PULSE into CCPR1L.
You may also add 1, 2, or 3 quarters of a pulse to the pulse length by putting 1, 2, or 3 into CCP1CON bits 4-5.
This assumes the Timer 2 prescaler (T2CON bits 0-1) are set to zero.
You may multiply both the period and pulse by 4 if you put 01 in T2CON bits 0-1
You may multiply both the period and pulse by 16 if you put 2 or 3 in T2CON bits 0-1
For example, I have a 32768 hz crystal clock. This gives 8192 instruction cycles/second. I want approximately 1Khz output so the best I can do is 8 instruction cycles per period. I want 25% duty cycle, so that would be 2 for the pulse width.
That's it. No muss, No fuss, No ugly multiplications by log2 or other yucky stuff like in the data sheets!
Edit-- changed program to enable/disable pwm using trisio, and to set ansel.
Edit again-- removed the set ansel, doesn't seem to be necessary.
Edit once again. It is not necessary to turn off the comparator so removed that code.
My understanding of PWM period and duty cycle are:
PERIOD is the number of instructions cycles you want it to take for one cycle of the output, on then off.
PULSE is the number of instructions cycles for the on portion of the cycle.
You put the (PERIOD - 1) into PR2.
You put the PULSE into CCPR1L.
You may also add 1, 2, or 3 quarters of a pulse to the pulse length by putting 1, 2, or 3 into CCP1CON bits 4-5.
This assumes the Timer 2 prescaler (T2CON bits 0-1) are set to zero.
You may multiply both the period and pulse by 4 if you put 01 in T2CON bits 0-1
You may multiply both the period and pulse by 16 if you put 2 or 3 in T2CON bits 0-1
For example, I have a 32768 hz crystal clock. This gives 8192 instruction cycles/second. I want approximately 1Khz output so the best I can do is 8 instruction cycles per period. I want 25% duty cycle, so that would be 2 for the pulse width.
Code:
;** note, case sensitivity turned off ( /c option), sorry for any inconvenience.
include p12F683.inc
__config _BOD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_OFF & _FCMEN_OFF & _LP_OSC
org 0
bsf status,rp0 ; bank 1
bsf trisio,2 ; make gp2/ccp1 an input, disabling pwm while we are setting up the registers
bcf status,rp0 ; back to bank 0
clrf gpio
clrf tmr2 ; clear timer2
bsf status,rp0 ; bank 1
movlw .7 ; set up for approx. 1 khz pwm with 25% duty cycle (32768 crystal)
movwf pr2 ; put period=8 instruction cycles into timer2 (set pr2 = period-1)
bcf status,rp0 ; bank 0
movlw 2 ; want pulse width = 25% of PWM period. = 2 instruction cycles.
movwf ccpr1L ;
movlw b'001100' ; add 0,1,2,or 3 quarters of an instruction cycle in bits 4-5 of ccp1con
movwf ccp1con ; last 4 bits (1100) set pwm mode to active-high
;movlw 0 ; multiplier, multiplies both period and pulse by 1,4, or 16
;movwf t2con ; 00=no multiply, 01=multiply by 4, 10 or 11 = multiply by 16
bsf T2Con,Tmr2on ; start timer2
bsf status,rp0 ; bank 1
bsf trisio,2 ; make gp2/ccp1 an output, enabling pwm
bcf status,rp0 ; back to bank 0
d2 goto d2
end
That's it. No muss, No fuss, No ugly multiplications by log2 or other yucky stuff like in the data sheets!
Edit-- changed program to enable/disable pwm using trisio, and to set ansel.
Edit again-- removed the set ansel, doesn't seem to be necessary.
Edit once again. It is not necessary to turn off the comparator so removed that code.
Last edited: