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







Wednesday, November 14, 2012

Pennybot restart

Knowing as always time is short for robot building I wanted to break down the tasks to build pennybot into smaller achievable tasks that would take 1-2 weekends (I only get a few hours spare per weekend) to complete but would aid in the final design.  Putting the chassis aside for now as it was mainly complete I concentrated on the microcontroller.  I hadn't touched a microcontroller for 4 years so it was pretty much relearning from scratch.

The first thing to learn was MPLAB X.  I could have stuck with MPLAB 8 but it was time to move on.  I also had invested in a PicKit 3 as a serial port wasn't an option on any of the laptops I wanted to use for development.  I used a simple "blink the leds" assembly program as the trial experiment.  

I soldered up a little PicKit 3 breadboard header and cable, plugged everything in a hoped.  I fell down the usual holes along the way (power from board or from pickit for example) and got burnt by having to be strict on the formatting in the MPLAB editor.  Previously the text files could be pretty sloppy and still work with mpasm.  However the formatting rules made me do things the proper way, which saved me time when I came back after a week or so to review some code.  

I also jumped pic models to a pic16f628.  That's right, I upgraded to a ~10 year old pic.  One day I'll join the real world.  Not having to have an external timing crystal (and getting two pins back) and the comparator module onboard were a big plus.  Also it was a very simple cutover from the pic16f84.  Finally I could buy (and did) 5 pic16f628 chips for $10 off ebay.  This means I have enough for this project and a few others so any investment in time in learning to program this model would pay off.  This did mean that C was pretty much out of the picture.  However I liked learning how to do things in assembly.  I enjoy having that real low level knowledge of what is going on even if the setup on some features (eg pwm) can get a bit messy.

I started development on a Windows 7 desktop.  After awhile I moved onto a linux laptop.  The only issue I had was the include statement.  In Linux (which is case sensitive) the include file is in capitals.  Everything else was fine.  So with MPLABX and the PicKit 3 sorted out it was time to do some real programs.