Tuesday, November 20, 2012

Pennybot line detection

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. 


    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







No comments: