This post sums up the work outlined in a previous thread, http://forum.allaboutcircuits.com/showthread.php?t=53089.
Weave is my Modular, Expandable Obstacle Avoiding Robot. It currently consists of three circuit boards: Sensor Array, Brains and Motor Drivers. More detail about these boards are given in the previous thread, so I'll just outline them here:
The Sensor Array creates two selectable modulated IR beams at 38kHz, and a 38kHz IR sensor/demodulator.
The brains contain a PIC16F886 and supporting circuitry, as well as a mini breadboard for on-robot prototyping.
The motor driver board contains two MOSFET H-Bridges and a linear 5v regulator. It is built in dead-bug style and will be the first module to get replaced in fact, split into motor control and power regulation, with low battery warning.
The program is written in ASM, and is attached for anyone who wants to have a look, copy, point out errors, etc. It essentially is fairly simple:
Constant Loop: Sends alternating pulses through each IR Led. After each set of two pulses, it checks to see if any signals were intercepted and sends motor control signals using a sort-of LUT.
Interrupt: The output of the IR detector is wired to RB0, the external interrupt pin. When a signal is intercepted, an ISR sees which IRED is currently emitting, and stores a result in that direction.
Demonstration video coming soon!
Thanks,
Barnaby
Weave is my Modular, Expandable Obstacle Avoiding Robot. It currently consists of three circuit boards: Sensor Array, Brains and Motor Drivers. More detail about these boards are given in the previous thread, so I'll just outline them here:
The Sensor Array creates two selectable modulated IR beams at 38kHz, and a 38kHz IR sensor/demodulator.
The brains contain a PIC16F886 and supporting circuitry, as well as a mini breadboard for on-robot prototyping.
The motor driver board contains two MOSFET H-Bridges and a linear 5v regulator. It is built in dead-bug style and will be the first module to get replaced in fact, split into motor control and power regulation, with low battery warning.
The program is written in ASM, and is attached for anyone who wants to have a look, copy, point out errors, etc. It essentially is fairly simple:
Constant Loop: Sends alternating pulses through each IR Led. After each set of two pulses, it checks to see if any signals were intercepted and sends motor control signals using a sort-of LUT.
Interrupt: The output of the IR detector is wired to RB0, the external interrupt pin. When a signal is intercepted, an ISR sees which IRED is currently emitting, and stores a result in that direction.
Demonstration video coming soon!
Thanks,
Barnaby
Rich (BB code):
;
; Author: Barnaby Walters
; Created: 27th March 2011
;
; For PIC: 16F886
; Default Radix: Hex
;
; Description: Contains the IR enable/detect loop. Lights different LEDs to indicate which direction an object is seen in
; Runs at 4MHz
;
; Currently: The interrupt handler gets called, but not all of the logic works properly
;
; * * * * * * * * * * * * * * * *
list p=16f886
include p16f886.inc
; Set up 16F886 Config Registers
__CONFIG _CONFIG1, _MCLRE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BOR_ON & _CP_OFF & _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _CPD_OFF
; For Config Bank 1: No MCLR Reset, no WDT, int. Osc no clkout, BOR On, Code protection, Low voltage protection â essectially, very few features.
__CONFIG _CONFIG2, _BOR40V & _WRT_OFF
; Set the BOR voltage to 4v, and we don't want any write protection
; Reserve Variables
tmr1 equ 20h ; Debug
tmr2 equ tmr1 + 1
temp equ tmr2 + 1
IRData equ temp + 1
w_temp equ IRData + 1
status_temp equ w_temp + 1
#define ls 0
#define rs 1
#define ll 2
#define rl 3 ; IRData structure: 7:4 = N/A; 3 = Right Lit; 2 = Left Lit; 1 = Right Signal; 0 = Left Signal
;firstAvailableRegister equ 0x20
org 0h
nop ; Allows ICD2 Debugger to work - not that I'm using that.
goto main ; Start main program
org 4h
goto isrRoutine
include "/Users/barnabywalters/Documents/Electronics/PIC Programs/16F886/Weave.inc" ; Port/Useful Definitions
; Interrupt Service Routine
isrRoutine
movwf w_temp
movf STATUS,w
movwf status_temp ; Save context
; Actual ISR
btfsc IRData,ll ; Is left emittor lit?
bsf IRData,ls ; If yes, store a signal received to the left
btfsc IRData,rl ; Is right emittor lit?
bsf IRData,rs ; If yes, store a signal received to the right
bsf portc,hb ; Light HB LED
bcf INTCON,INTF ; Clear interrupt flag
movf status_temp,w ; Restore context
movwf STATUS
swapf w_temp,f
swapf w_temp,w
retfie ; Return
; * * * * * * * * * * * SUBROUTINES * * * * * * * * * * * * * * *
; Initalisation Routine
init
clrf PORTA
clrf PORTB
clrf PORTC
banksel OSCCON ; switches to bank 1. We need to be here to mess about with TRIS registers
movlw b'01100001' ;
movwf OSCCON ; Osc Config: 0 (un) , 110 (4Mhz) , 000 (Rd Only) , 1 (Use internal Clk)
movlw b'00000000' ;
movwf TRISA ; PORTA = all outputs. A0 = Right indicator A1 = Left Indicator
movlw b'00000001' ;
movwf TRISB ; PORTB 0:3 used. B1 = Right Enable B2 = Left Enable B0 = Sensor Input
movwf WPUB ; Weak pull-up on RB0
movlw b'00000000' ;
movwf TRISC ; PORTC = outputs. C3 = HB LED. Motors not used in this app (yet)
movlw b'1000'
movwf TRISE ; PORTE 3 (MCLR) = Input
banksel ANSELH
bcf ANSELH,4
banksel OPTION_REG
bcf OPTION_REG,NOT_RBPU ; Enable RB Pull Ups
bcf OPTION_REG,INTEDG ; Interrupt triggered on falling edge @ RB0
movlw b'10010000'
movwf INTCON ; Enable unmasked interrupts, Enable interrupt on RB0
banksel PORTA ; Switch to bank 0 so we can move on with the program
return ; Return to the program
; Delay Routines:
D30IRCycles ; Delays program flow for 30 cycles @ 38kHz 'On' time for IREDs
movlw d'2'
movwf tmr2
movlw d'130' ; 30 IR Cycles = 780 instruction cycles. GOTO = 2 instruction cycles
movwf tmr1 ; This timer will have to be completely decremented two times for the full 780 cycles
D30IR_Delay
decfsz tmr1,F
goto D30IR_Delay ; Cycle 195 times
movwf tmr1
decfsz tmr2,F
goto D30IR_Delay ; Go back and cycle twice
return
D15IRCycles ; Delays program flow for 15 cycles @ 38kHz 'Off' time for IREDs
movlw d'195' ; GOTO = 2 cycles. 2 * 195 = 390 instructions = 15 IR Cycles
movwf tmr1
D15IR_Delay
decfsz tmr1,f
goto D15IR_Delay
return
; Look-Up Tables:
motorControlLUT
movf IRData,w
andlw b'11' ; Mask off the bits we're interested in (1:0)
movwf temp ; Store offset
movlw high tableStart ; Get the high order part of address of tableStart
movwf PCLATH ;
movlw low tableStart ; Get low order address of tableStart
addwf temp, w ; Add the offset
btfsc STATUS, C ; Did it overflow?
incf PCLATH,f ; If yes, add one to PCLATH
movwf PCL ; Modify PCL and use the table
tableStart
goto forwards
goto softbackright
goto softbackleft
goto hardleft
; * * * * * * * * * * Main Program * * * * * * * * * *
main
call init ; Set up ports, etc
; Program structure: Constantly alternate between IR LEDs. Each one on for 30 cycles, the off for 15 cycles as per datasheet
sensorPollLoop
bcf portc,hb ; Turn of HB LED
call D15IRCycles ; Hold LEDs off for the required time
bsf PORTB,2 ; Turn on the left IRED (Robot perspective)
bsf IRData,ll ; Left IRED currently emitting.
call D30IRCycles ; Hold it on for a certain amount of time
bcf IRData,ll ; Left IRED not currently emitting
bcf PORTB,2 ; Turn off the left IRED
call D15IRCycles ; Hold LEDs off for the required time
bsf PORTB,1 ; Turn on the right IRED (Robot perspective)
bsf IRData,rl ; Right IRED currently emitting
call D30IRCycles ; Hold it on for a certain amount of time
bcf IRData,rl ; Right IRED not currently emitting
bcf PORTB,1 ; Turn off the right IRED
; One complete sensor poll finished
; Now: See what data we have. For the moment, that means copying the data in IRData 3:2 to PORTA 3:2. How convenient
movf IRData,w ; Pop value of IRData into the W. Reg
movwf PORTA ;
and copy it into PORTA. Sorted! That's indicated the direction the signal was found in.
bcf INTCON,GIE ; Disable interrupts while sorting out motor control
call motorControlLUT ; Get the motor control signal required from the LUT
movwf PORTC ; Move the signal into PORTC
bsf INTCON,GIE ; Enable interrupts again
clrf IRData ; Clear data from last sensor poll loop execution
goto sensorPollLoop
end