; irsens3.asm  3 channel IR sensor for robot
; Written for 12C508 PIC microcontroller

;   by Dale A. Heatherington Sept 23 1999
;
;---------------------------------------------------------------------
;
;   PIC12C508 pin assignments
;
; 1     +5v
; 2     OUT RIGHT (Right object detected, low true)
; 3     OUT LEFT ( Left object detected, low true)
; 4     IR receiver input (Low = pulse received)
; 5     Right LED drive (low true)
; 6     Center LED drive
; 7     Left LED drive
; 8     GND
;
;Note: Both pins 2 and 3 go low when a center object is detected
;
;;----------------------------------------------------------------------
;;This program is free software; you can redistribute it and/or modify  
;;it under the terms of the GNU General Public License as published by      
;;the Free Software Foundation; either version 2 of the License, or         
;;(at your option) any later version.                                       
;;
;;This program is distributed in the hope that it will be useful,       
;;but WITHOUT ANY WARRANTY; without even the implied warranty of            
;;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             
;;GNU General Public License for more details.                              
                                                                          
;;You should have received a copy of the GNU General Public License     
;;along with this program; if not, write to the Free Software               
;;Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
;;------------------------------------------------------------------------    


	RADIX	        dec
	processor	12c508


	__CONFIG h'0FEA'		;Internal 4 RC mhz osc
        

                
;Chnage this to point to your mpasm include directory
        
        include "../../../mpasm/p12c508.inc"




 
;------------------------------------------------------------

        
;GPIO  input bits
IR1     equ     3      ;IR sensor input (low true)

;GPIO output bits
OUT_L    equ     4      ;object detection output bits (low true)
OUT_R    equ     5

LED_L    equ     0
LED_C    equ     1      ;LED driver outputs (low true)
LED_R    equ     2

LEDs    equ     7


;variables


i_main          equ     10h
integ_L         equ     11h
integ_C         equ     12h
integ_R         equ     13h
j_main          equ     14h



;--------------------------------------------------



;    MACROS



;;Drive the integrator up 1 count if return pulse is present
;; but count down by 1 if the pulse is not present.

integrate_pulse MACRO   N,inbit
                local   _ip_seen, _ip_done

	btfss GPIO,inbit  ; //sample IR sensor (low = pulse seen)
	goto  _ip_seen;
	movf  N,w ;
	btfss STATUS,Z ;   //Don't wrap below zero
	decf  N,f;         //Decrement integrator if pulse not there
	goto  _ip_done;
_ip_seen
	incf  N,f;        //increment if pulse is there
        nop
	btfsc STATUS,Z;   //Don't wrap from 255 to 0
	decf  N,f;
_ip_done
        ENDM


;;Drive the integrator up 1 count if pulse is NOT present
;; but decrement it if a pulse IS present. (pulse is not supposed to be here)
integrate_space MACRO   N,inbit
                local   _is_seen, _is_done

        btfsc GPIO,inbit  ; //sample IR sensor (high = pulse not seen)
	goto  _is_seen;
	movf  N,w;
	btfss STATUS,Z;   //If it's zero don't decrement it
	decf  N,f;
	goto  _is_done;
_is_seen
	incf N,f;
        nop
	btfsc   STATUS,Z ; //Don't wrap around
	decf N,f;
_is_done

        ENDM
        

;;Make the output go LOW (true) if the integrator
;;value is greater than 127.        
output  MACRO   N,outbit
        local   _one_out, _output_done
        
        btfss   N,7
        goto    _one_out
        bcf     GPIO,outbit
        goto    _output_done
        
_one_out
        bsf     GPIO,outbit

_output_done
        endm
        



;;One cycle of 40 KHZ (less 10uS for overhead in other code)
;This take 15uS to execute. A complete cycle is 25 uS long.        
cycle_leds      MACRO LED

        bcf     GPIO,LED
        nop
       	nop
        nop
        nop   
	nop           
	nop   
	nop   
	nop   
        nop     
        nop
        nop
        bsf     GPIO,LED
        nop
        nop

        endm


delay_16us      MACRO
        local   _loop
        movlw   4
        movwf   j_main
_loop   
        decfsz  j_main
        goto    _loop
        nop
        nop
        endm
                
        
      
        

;;Subtract 2 from the integrator

        
leak_down       MACRO   N
         local   _leak_exit
         movf   N,f             ;Test for zero
         btfsc  STATUS,Z
         goto   _leak_exit      ;Don't go below zero
         decfsz N,f             ;decrement by 2
         decf   N,f
_leak_exit
        endm
        


;---------------------------------------------------------------------

;Actual code starts here...



	ORG 0
 
main_code
        movwf   OSCCAL      ;Internal 4 mhz osc calibration value
	clrf    STATUS
	movlw   0ffh
	movwf   GPIO
        clrf    integ_C
        clrf    integ_L
        clrf    integ_R
        movlw   8               ;Bit 3 is the IR sensor input
	tris    GPIO            ; 
        movlw   0C0h
	option
          
label_0001                      ;Top of main loop

; Emit IR pulses on left LED  and register response in integ_L.
	movlw   20
        movwf   i_main          ; Loop 20 times for 20 cycles of 40 khz
                                ; This makes a 500uS IR pulse
pulse_loop_L         
        cycle_leds LED_L
        integrate_pulse integ_L,IR1
        decfsz  i_main
        goto    pulse_loop_L
 

	movlw   20
        movwf   i_main          ;loop 20 times with LED OFF
space_loop_L                    ;for about 500uS with no IR pulse
        delay_16us
        integrate_space integ_L,IR1
        decfsz  i_main
        goto    space_loop_L
        

;Emit IR pulses on right LED  and register response with integ_R.

	movlw   20
        movwf   i_main          ; Loop 20 times for 20 cycles of 40 khz
        
pulse_loop_R         
        cycle_leds LED_R      
        integrate_pulse integ_R,IR1
        decfsz  i_main
        goto    pulse_loop_R
 

	movlw   20
        movwf   i_main          ;loop 20 times with LEDs OFF
space_loop_R
        delay_16us
        integrate_space integ_R,IR1
        decfsz  i_main
        goto    space_loop_R
        

;Emit IR pulses on center LED and register response with integ_C.

	movlw   20
        movwf   i_main          ; Loop 20 times for 20 cycles of 40 khz
        
pulse_loop_C         
        cycle_leds LED_C      
        integrate_pulse integ_C,IR1
        decfsz  i_main
        goto    pulse_loop_C
 

	movlw   20
        movwf   i_main          ;loop 20 times with LEDs OFF
space_loop_C
        delay_16us
        integrate_space integ_C,IR1
        decfsz  i_main
        goto    space_loop_C

;;Now we check the integrators
        
        btfsc   integ_C,7       ;See if Center integrator has crossed threshold
        goto    out_center    
        output  integ_L,OUT_L   ;Else output Left or right results
        output  integ_R,OUT_R
        goto    leak
        
out_center
        bcf     GPIO,OUT_L      ;set both outputs low (TRUE) if center
        bcf     GPIO,OUT_R       
        
leak
        leak_down integ_L       ;Bias the integrators to the down side...              
        leak_down integ_R       ;...for random or no inputs.
        leak_down integ_C
                
       
          
      	goto label_0001         ;Infinite main loop


	END
