As the primary detector sensors I wanted to use IR detectors as I had in previous robots. Key to this is the generation of a 38khz square wave (50% duty cycle) which the IR detectors are tuned to. In other robots I had used the circuit described in David Cook's Intermediate Robot Building book. There are others based on 555 timer chips to. However the pic16f628 has a PWM module and can output a PWM signal on one pin (RB3). This meant one less extra IC chip and associated parts (resistors/capacitors). However the setting up of the PWM was a little more esoteric.
I recommend reading the Microchip "PICmicro Mid-Range MCU Family Reference Manual". The section on PWM makes the setup of PWM a lot clearer as there are some worked examples of the formulas used. Without these I would have been pretty lost in time conversion hell.
Setting up PWM requires two main steps. First is setting the frequency of the PWM. The second is setting the duty cycle of the PWM. Both the pic16f628 reference manual the the Mid-Range reference manual describe the formulas to do this. Where things get interesting is that the PWM duty cycle is 10 bits and thus spread across two registers (CCPR1L and CCP1CON<5:4>). Below is a worked example showing this.
First I set the PWM frequency to 38khz (ish). For the TMR2 prescale I looked at the examples in the reference manual as a guide of what to set. Like most of technology it's a case of seeing what someone else did and changing it to fit your specific case. Via the equation with a 4mhz clock and a TMR2 prescale of 1
PWM period = (PR2 +1) * 4 * TOSC * TMR2 prescale
1/38kHz = (PR2 +1) * 4 * 1/4MHz * 1
26us = (PR2+1) * 4 * 0.25
26us = (PR2+1) * 1
25 = PR2
and the code with comments
; set pwm period
; 0x19 == 25 decimal. So via equation
; 25+1 * 4 * 0.25 * 1 = 26
; 1/26 == 38khz ish
banksel PR2
movlw 0x19
movwf PR2
Then I set the duty cycle to 50%. This means that the frequency will be twice that of the pwm. Ie for each PWM period the duty cycle has to change twice (on, then off). Thus the value to be put into the registers will be 0x34 (decimal 52 - 26*2). This is split across the two registers. The easiest way I found to do this was write out 0x34 as binary
0011 0100
Now this needs to be 10 bits, so the left most bits will be '00'
0000 1101 00
So CCPR1L will be '0000 1101' (0x0d) and CCP1CON<5:4> will be '00' (CCP1CON = 0x0c). Code and comments below
; set pwm duty cycle to 50%
; so need duty cycle to be twice pwm period - ie 52 = 0x34
; since Tosc is in both pwm and duty cycle equation they cancel out
; remember split across bits 5/4 of ccp1con and ccpr1l
; ie 0000 1101 00
; 0x 0 d 0
banksel CCP1CON
movlw 0x0c
movwf CCP1CON
movlw 0x0d
movwf CCPR1L ; duty cycle 0x34 - ie 52 decimal
; set tmr2 prescaler
banksel T2CON
movlw 0x00
movwf T2CON
; turn on timer 2
bsf T2CON, TMR2ON
On the first attempt I got the duty cycle numbers wrong and saw no frequency output. Stumped I ending up measuring the voltage on pin RB3. It was 5V. So the voltage was at VDD which is 5V which means I had a duty cycle of over 100%. Reworking the numbers I spotted my error and fixed things up. With a duty cycle of 50% the voltage was half VDD as expected.
On a side note I used a Casio FX-100d calculator to do the number crunching. It's over 20 years old (I had it in high school) and is still running on the original battery. Not sure what battery technology it has but I'm assuming it's an arc reactor subtype.5:4>5:4>
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment