The first piece of functionality I wanted to get working was the white line edge detection. Previously I had used photoresistors and a LM393 comparator chip. This time I wanted to try using LED Infra-red (IR) emitters and IR phototransitors detectors. This was to reduce the impact of environmental light on the edge detection sensors. Rather than a separate comparator chip I would use the comparator module in the pic16f628. I had some nice 3mm LED IR emitter and 3mm phototransistor in a dual plastic housing that I had gotten from an old robot kit I had purchased purely for parts. Not knowing the specs of either part I used a 1K resistor on the IR emitter. For the phototransistor I wasn't sure the part was actually a phototransister. As suggested in some example circuits I was using a 50K resistor in series. There was very little response (ie voltage change) to changes in light level, less than 0.2 volts. Trying a few different parts the result was the same. Finally I guessed this was a IR only phototransistor. Putting my finger to cover the IR LED and phototransistor (ie bouncing the IR led output back to the transistor) the transistor turned on - success! The voltage range of the test point on the photo transistor from off to on was approx 4.8V (off) to 0.4V (on).
Over on the microcontroller side of things I was using the comparator module as two common reference comparators (setting CM<2:0> = 011). For the reference voltage I used a 10K pot to divide the 5V input and thus be able to tune the trigger point of the comparator. I setup an ISR to trigger every time the comparator tripped. The ISR incremented a counter and the main loop displayed this count in binary on 4 leds (the counter rolled over at 10). Initially I was getting some twitchy responses with double counts, etc. I added a 50ms delay in the ISR on the reading of the sensor and this was eliminated. In addition to the counter being displayed I also toggled an led on port RA3 depending of the comparator output. Code and comments below. 2:0>
include "P16F628A.INC" ;include the defaults for the chip
list p=16f628a
__config (_CP_OFF & _CPD_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF)
; ra0 / ra1 = inputs V-
; ra2 common V+
; ra3 output to led
; variables
cblock 0x20
OUTCOUNT ; interrupt code counter
count ;used in delay routine
count1 ;used in delay routine
counta ;used in delay routine
countb ;used in delay routine
endc
#define W_TEMP 0x70 ; common memory area across all banks
#define STATUS_TEMP 0x71 ; temp vars for ISR
org 0
goto init ; skip ISR code
;
; ISR code
;
org 4
movwf W_TEMP ; Save W & STATUS, etc
swapf STATUS, W
bcf STATUS, RP0
movwf STATUS_TEMP ; end ISR save bits
incf OUTCOUNT,1 ; COUNT +1, then check and reset count if needed
movlw 0x0A ; put 10 in W
subwf OUTCOUNT,0 ; subtract 10 from count to see if count > 10
btfsc STATUS,0 ; check carry flag, skip if clear
clrf OUTCOUNT ; reset count to 0
call Delay50 ; wait 50ms for switch to get stable
bcf STATUS,RP0 ; select bank 0
btfsc CMCON,C2OUT ; if c2out is 1
bsf PORTA,3 ; turn on ra3 led
btfss CMCON,C2OUT ; if c2out is 0
bcf PORTA,3 ; turn off ra3 led
bcf PIR1, CMIF ; clear pending interrupts
swapf STATUS_TEMP, W ; restore W & STATUS
movwf STATUS
swapf W_TEMP,F
swapf W_TEMP,W
retfie ; end ISR end bits
init
movlw 0x03 ; init comparator mode
movwf CMCON ; CM<2:0> = 011
bsf STATUS,RP0 ; select bank 1
movlw 0x07 ; init data direction
movwf TRISA ; ra2/0 as inputs, ra 4/3 as output
movlw 0x00
movwf TRISB ; all port b as output - for counter
bcf STATUS,RP0 ; select bank 0
movf CMCON,F ; read cmcon to end change condition wrt interrupt setup
bcf PIR1, CMIF ; clear pending interrupts
bsf STATUS, RP0 ; select bank 1
bsf PIE1, CMIE ; enable comparator interrupts
bcf STATUS,RP0 ; select bank 0 - determine initial state of comp output
clrf PORTB ; clear portb
btfsc CMCON,C2OUT ; if c2out is 1
bsf PORTA,3 ; turn on ra3 led
btfss CMCON,C2OUT ; if c2out is 0
bcf PORTA,3 ; turn off ra3 led - finished initial state
clrf OUTCOUNT ; init COUNT at 0
bsf INTCON, PEIE ; enable peripheral interrupts
bsf INTCON, GIE ; enable global interrupts
main
movf OUTCOUNT,0 ; COUNT to W
movwf PORTB ; display count in hex on leds
goto main
;Delay routines
Long_Delay
movlw d'50' ;delay 5 seconds
call Delay100W
return
Delay100W movwf count ;delay W x 100mS
d2 call Delay100 ;maximum delay 25.5 seconds
decfsz count ,f
goto d2
return
Delay255 movlw 0xff ;delay 255 mS
goto d0
Delay100 movlw d'100' ;delay 100mS
goto d0
Delay50 movlw d'50' ;delay 50mS
goto d0
Delay20 movlw d'20' ;delay 20mS
goto d0
Delay10 movlw d'10' ;delay 10mS
goto d0
Delay1 movlw d'1' ;delay 1mS
goto d0
Delay5 movlw 0x05 ;delay 5.000 ms (4 MHz clock)
d0 movwf count1
d1 movlw 0xC7
movwf counta
movlw 0x01
movwf countb
Delay_0 decfsz counta, f
goto $+2
decfsz countb, f
goto Delay_0
decfsz count1 ,f
goto d1
return
;end of Delay routines
end
2:0>
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment