; TITLE 'Infra Red Proximity Detector - uses Sharp 38 or 40KHz IRM ; ; I included the "include" file for the 508 for reference while programming ; LIST P = 12C508, F = INHX8M ; P12C508.INC Standard Header File, Version 1.02 Microchip Technology, Inc. ;========================================================================== ; Verify Processor ;========================================================================== IFNDEF __12C508 MESSG "Processor-header file mismatch. Verify selected processor." ENDIF ;========================================================================== ; Register Definitions ;========================================================================== W EQU H'0000' F EQU H'0001' ;----- Register Files ----------------------------------------------------- INDF EQU H'0000' ; Uses FSR to address data mem. TMR0 EQU H'0001' ; 8 bit real time clock/counter PCL EQU H'0002' ; Low order 8 bits of PC STATUS EQU H'0003' ; STATUS FSR EQU H'0004' ; Indirect data memory addr pointer OSCCAL EQU H'0005' ; Calibration data for osc. GPIO EQU H'0006' ; General Purpose I/O ;----- STATUS Bits -----------Page 14-------------------------------------- GPWUF EQU H'0007' ; GPIO reset bit PA0 EQU H'0005' ; Program Page preselect NOT_TO EQU H'0004' ; Time Out bit NOT_PD EQU H'0003' ; Power Down bit ZERO EQU H'0002' ; Zero bit DC EQU H'0001' ; Digit carry/*borrow bit CARRY EQU H'0000' ; carry/*borrow bit ;----- OPTION Bits -----------Page 15-------------------------------------- NOT_GPWU EQU H'0007' ; Enable wake-up on pin change NOT_GPPU EQU H'0006' ; Enable weak pull-ups T0CS EQU H'0005' ; Timer0 clock source select T0SE EQU H'0004' ; Timer0 sources edge select PSA EQU H'0003' ; Prescalar assignment bit PS2 EQU H'0002' ;\ PS1 EQU H'0001' ; > Prescalar rate select bits PS0 EQU H'0000' ;/ ;========================================================================== ; RAM Definition ;========================================================================== __MAXRAM H'3F' ;========================================================================== ; Configuration Bits ;========================================================================== _MCLRE_ON EQU H'0FFF' _MCLRE_OFF EQU H'0FEF' _CP_ON EQU H'0FF7' _CP_OFF EQU H'0FFF' _WDT_ON EQU H'0FFF' _WDT_OFF EQU H'0FFB' _LP_OSC EQU H'0FFC' _XT_OSC EQU H'0FFD' _IntRC_OSC EQU H'0FFE' _ExtRC_OSC EQU H'0FFF' __CONFIG ( _MCLRE_OFF & _CP_OFF & _WDT_OFF & _IntRC_OSC ) ;========================================================================== ; Program Variables ;========================================================================== #define LEFTDETECT GPIO,5 ; Pin 2 = GP5 = Bit 5 #define RIGHTDETECT GPIO,4 ; Pin 3 = GP4 = Bit 4 #define INHIBIT GPIO,3 ; Pin 4 = GP3 = Bit 3 #define RIGHTLED GPIO,2 ; Pin 5 = GP2 = Bit 2 #define IRDETECT GPIO,1 ; Pin 6 = GP1 = Bit 1 #define LEFTLED GPIO,0 ; Pin 7 = GP0 = Bit 0 #define LLIMIT D'30' ; Lower limit of allowable hits in a window #define LHITLIM D'5' ; Lower hits limit #define UMISSLIM D'20' ; Upper miss limit LIST WAIT EQU 9 ; Location for counter for time delay loop FAKEHIT EQU D'14' ; Counter for false detections LHITS EQU D'15' ; Counter for detections found properly on the left RHITS EQU D'16' ; Counter for detections found properly on the right FAKEHIST EQU D'17' ; History of bad hits to overcome noise SLHITS EQU D'11' ; Number of hits in a row SLMISS EQU D'13' ; Number of misses in a row SRHITS EQU D'18' ; Number of hits in a row SRMISS EQU D'19' ; Number of misses in a row ;================================ ; Main Code = ;================================ ORG 0x1FF ;MOVLW 0x50 ; My EPROM calibration value,remove for OTPs start ORG 0x000 MOVWF OSCCAL ; Store the factory osc. calibration value MOVLW B'11001010' ; Set pins 4,6 as inputs, 2,3,5,7 as outputs TRIS GPIO ; Configure pins as either I or O MOVLW B'01000000' ; Set OPTION bits (Weak pullups enabled) OPTION ; Implement OPTION bits CLRF FAKEHIST ; History of bad hits CLRF SLHITS ; Good hits "in a row" history CLRF SLMISS ; Misses "in a row" history CLRF SRHITS CLRF SRMISS MOVLW B'11001010' ; Make sure that GP1 and GP3 are '1' on read MOVWF GPIO main ;*************************************************************************** ; This version of my IR detector recognizes that there is background noise * ; out there that needs to be overcome to get good readings no matter what. * ; * ; It alternates readings of both the left and the right IR LEDs each of * ; them cycled at 40KHz for 2.5ms on and 2.5ms off, a 50% duty cycle. * ; During the 'off' cycle we will look for false hits, denoting noise in * ; our environment. It saves these noise readings, if subsequent readings * ; are higher, then the higher reading is saved, if lower, then 1/4 of the * ; newer reading will be subtracted from the history. So noise levels are * ; reduced faster than they are raised so a signal can still sneak in there.* ; Then the IR LED is flashed at 40KHz and a reading is taken on every * ; cycle. These readings are taken in the same cycle "time slots" as the * ; ones taken in the 'off' cycle. In each case, 100 cycles are sampled. * ; After a full on/off cycle, a reading is considered good if there are more* ; good detections than false hits AND there are at least 20 good hits. * ; A counter is incremented every time there is a good hit on any given * ; side, at that time, a miss counter is decremented. When there is a bad * ; cycle, the miss counter for that side is incremented and the hit counter * ; is decremented. When the threshhold for hits is passed, the detect is * ; indicated on that side and the miss counter is zeroed out. Conversely, * ; if the miss threshhold is exceeded (always larger than the hit one) then * ; a detect is disabled and the hit counter is zeroed. In this way you get * ; a sort of lock on a good signal that takes effort to lose. Also, noise * ; is rejected better and you have a more solid result. * ; * ; Sampling times, threshholds and limits were arrived at completely by hit* ; and miss. Eventually, I stopped fiddling and declared "good enough" * ; because the more I fiddled, the worse it seemed to get... * ; * ; Revision 2.0 2/16/98 Copyright Dennis Clark and TTT Ent. * ;*************************************************************************** noflash BTFSC INHIBIT ; This needs an external pullup, not there yet. GOTO do_looks ; If /inhibit is one, do your thing. CLRF FAKEHIST ; History of bad hits CLRF SLHITS ; Good hits "in a row" history CLRF SLMISS ; Misses "in a row" history CLRF SRHITS CLRF SRMISS MOVLW B'11001010' ; Make sure that GP1 and GP3 are '1' on read MOVWF GPIO GOTO noflash do_looks call do_left ; deal with left looking stuff call do_right ; deal with right side stuff goto noflash ; look again ;================================ ; SUBROUTINES = ;================================ do_left CALL delayloop ; Look for false hits when IR LEDs are off CALL pulseleft ; Pulse the left IR LED at 40 KHz MOVF FAKEHIST,W ; Get current "noise" level SUBWF LHITS,W ; LHITS - FAKEHIST => W BTFSS STATUS,CARRY ; C=1 means LHITS >= FAKEHIST GOTO nlgood ; IR detector didn't get a hit through the noise MOVLW LLIMIT ; Get the lower limit for allowable hits SUBWF LHITS,W ; LHITS - LLIMIT => W BTFSS STATUS,CARRY ; C=1 means that LHITS >= LLIMIT = good hit GOTO nlgood ; Nope, not good enough - too noisy maybe clgood INCF SLHITS,F ; increment number of good hits DECF SLMISS,F ; decrement miss counter MOVLW LHITLIM ; Lower hit limit SUBWF SLHITS,W ; enough good ones in a row? BTFSS STATUS,CARRY ; C=1 means SHITS >= limit GOTO lldone ; not yet lgood BSF LEFTDETECT ; Turn on the left Visible LED CLRF SLMISS ; clear miss counter GOTO lldone ; Now lets look right nlgood INCF SLMISS,F ; increment number of misses DECF SLHITS,F ; reduce hits counter MOVLW UMISSLIM ; Upper missed ones limit SUBWF SLMISS,W ; too many bad ones in a row? BTFSS STATUS,CARRY ; C=1 means SMISS >= limit GOTO lldone ; not bad enough yet no_left ; No obstacle to the left, so BCF LEFTDETECT ; Turn off the left visible LED CLRF SLHITS ; clear the hits counter lldone retlw 0 do_right CALL delayloop ; Look for false hits when IR LEDs are off CALL pulseright ; Pulse the right IR LED at 40 KHz MOVF FAKEHIST,W ; Get current "noise" level SUBWF RHITS,W ; RHITS - FAKEHIST => W BTFSS STATUS,CARRY ; C=1 means LHITS >= FAKEHIST GOTO nrgood ; IR detector didn't get a hit through the noise MOVLW LLIMIT ; Get the lower limit for allowable hits SUBWF RHITS,W ; RHITS - LLIMIT => W BTFSS STATUS,CARRY ; C=1 means that LHITS >= LLIMIT = good hit GOTO nrgood ; Nope, not good enough - too noisy maybe crgood INCF SRHITS,F ; increment number of good hits DECF SRMISS,F ; decrement miss counter MOVLW LHITLIM ; Lower hit limit SUBWF SRHITS,W ; enough good ones in a row? BTFSS STATUS,CARRY ; C=1 means SHITS >= limit GOTO lrdone ; not yet rgood BSF RIGHTDETECT ; Turn on the left Visible LED CLRF SRMISS ; clear miss counter GOTO lrdone ; start over nrgood INCF SRMISS,F ; increment number of misses DECF SRHITS,F ; reduce hits counter MOVLW UMISSLIM ; Upper missed one limit SUBWF SRMISS,W ; too many bad ones in a row? BTFSS STATUS,CARRY ; C=1 means SMISS >= limit GOTO lrdone ; not bad enough yet no_right ; No obstacle to the left, so BCF RIGHTDETECT ; Turn off the left visible LED CLRF SRHITS ; clear the hits counter lrdone retlw 0 delayloop MOVLW D'100' MOVWF WAIT ; This creates a delay CLRF FAKEHIT ; Clear out for checking loop BCF LEFTLED ; Make sure IR LEDs are off BCF RIGHTLED ; NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP ; NOP ; NOP ; NOP ; NOP ; BTFSS IRDETECT ; Look for a false hit INCF FAKEHIT,F ; note the false detect NOP ; NOP ; DECFSZ WAIT,F ; goto loop MOVF FAKEHIST,W ;Get historic false readings SUBWF FAKEHIT,W ;FAKEHIT - FAKEHIST => W BTFSS STATUS,CARRY ;if C=1 then FAKEHIT >= FAKEHIST GOTO newless ;Go here if FAKEHIT < FAKEHIST MOVF FAKEHIT,W ;Get current # of false hits MOVWF FAKEHIST ;And save the new higher number GOTO bdone ;my job here is done newless RRF FAKEHIT,F ; ; RRF FAKEHIT,F RRF FAKEHIT,W ; ANDLW 0x3f ;divide by 4 SUBWF FAKEHIST,F ;FAKEHIST - (FAKEHIT/4) => FAKEHIST, save lower number bdone RETLW 0 pulseleft MOVLW D'100' MOVWF WAIT ; Pulses the left IR led at 40 KHz CLRF LHITS ; Clear out the count for now leloop BSF LEFTLED ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; BCF LEFTLED ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; BTFSS IRDETECT ; Look for a detection INCF LHITS,F ; And record them (moved this up a bit) NOP ; NOP ; DECFSZ WAIT,F GOTO leloop RETLW 0 pulseright MOVLW D'100' MOVWF WAIT ; Pulses the right IR led at 40KHz CLRF RHITS ; Clear out hit counter riloop BSF RIGHTLED ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; BCF RIGHTLED ; NOP ; NOP ; NOP ; NOP ; NOP ; NOP ; BTFSS IRDETECT ; Look for detections INCF RHITS,F ; and record them NOP ; NOP ; DECFSZ WAIT,F GOTO riloop RETLW 0 END