#include ; __CONFIG _BODEN_ON & _CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF & _HS_OSC errorlevel -302 ;suppress "not in bank 0" message WREGsave EQU H'40' STATUSsave EQU H'41' FSRsave EQU H'42' PCLATHsave EQU H'43' IndexRead EQU H'44' IndexWrite EQU H'45' Temp EQU H'46' ANRESH EQU H'47' ;Analog value MSByte ANRESL EQU H'48' ;Analog value LSByte WhatsNew EQU H'49' ;Update commands register DataOutIR1 EQU H'4A' DataOutIR2 EQU H'4B' DataOutUS1 EQU H'4C' DataOutUS2 EQU H'4D' DataOutIR1Bis EQU H'4E' DataOutIR2Bis EQU H'4F' DataOutUS1Bis EQU H'50' DataOutUS2Bis EQU H'51' COUNT1 EQU H'21' ;Temporary count register COUNT2 EQU H'22' ;Temporary count register RESL EQU H'23' ;Capture time LSByte RESH EQU H'24' ;Capture time MSByte SensorState EQU H'25' ;Status US CheckMe EQU H'26' ;Check Measurement CNT1 EQU H'27' ;Temporary count register CNT2 EQU H'28' ;Temporary count register CONT1 EQU H'29' ;Temporary count register CONT2 EQU H'2A' ;Temporary count register TIMER1 EQU H'2B' ;Temporary count register TIMER2 EQU H'2C' ;Temporary count register ORG 0 GOTO RESET ; ORG 4 GOTO INTERRUPT ; 0x0004 ; **************************************************** ; * Main Prog * ; **************************************************** RESET ;****************** ; Bank 0 Registers ;****************** ; Clear the Ports clrf PORTA clrf PORTB clrf PORTC clrf DataOutIR1Bis clrf DataOutIR2Bis clrf DataOutUS1Bis clrf DataOutUS2Bis ;****************** ; Bank 1 Registers ;****************** ; Set RP0 bsf STATUS,RP0 ; Configure PORTC: CCP1 (RC2) as an input, and all other pins ; as outputs, (RC0 = INIT, RC5 = BINH) ; Configure PORTA: IR signal (RA0) as an input as well as Vref+ and Vref- ; (RA3, RA2) MOVLW B'00001101' MOVWF TRISA MOVLW B'00111110' MOVWF TRISB movlw B'00000100' movwf TRISC bcf STATUS,RP0 ; Clear RP0 ; Initial conditions MOVLW B'00000011' ; STOP signal, ALL measuring MOVWF WhatsNew MOVLW B'00000001' MOVWF SensorState clrf DataOutIR1Bis clrf DataOutIR2Bis clrf DataOutUS1Bis clrf DataOutUS2Bis CALL SetupSSP ; Initialise I2C Communication CALL SetupAnalog ; Initialise Analog Input PortA0 CALL SetupCCP ; Initialise Capture & Timer1 modules CALL EnableAllInt ; Start Interrupts call DEL_50 ; Delay 50 ms MAINLOOP BCF PORTC,6 ; Switch Led Off BCF PORTC,7 ; Switch Led Off BTFSC WhatsNew,6 ; Reset? GOTO RESET BTFSS WhatsNew,7 ; Wait? GOTO MAINLOOP MOVF WhatsNew,W MOVWF CheckMe BTFSS CheckMe,0 ; IR? GOTO ChkBranch IRAction BSF PORTC,6 ; Switch Led On CALL IRMEASUREMENT ChkBranch BTFSC WhatsNew,6 ; Reset? GOTO RESET BTFSS WhatsNew,7 ; Stop & Wait? GOTO MAINLOOP BTFSC CheckMe,1 ; US? BTFSS WhatsNew,2 ; USn-1 still busy? GOTO MAINLOOP BTFSS SensorState,0 ; This US still busy? GOTO MAINLOOP USAction BCF PORTC,6 ; Switch Led Off BSF PORTC,7 ; Switch Led On bcf SensorState,0 ; Sensor is busy now... bcf WhatsNew,2 CALL USMEASUREMENT GOTO MAINLOOP ; Loop main program ; **************************************************** ; * Measurement loops * ; **************************************************** IRMEASUREMENT BSF ADCON0,GO ; Start AD conv IRLOOP BTFSC ADCON0,GO ; Wait until AD conv is done GOTO IRLOOP MOVF ADRESH,W ; Read High Byte (2 MSB bits) MOVWF ANRESH ; Store High Byte BSF STATUS,RP0 MOVF ADRESL,W ; Read Low Byte : Bank 1 BCF STATUS,RP0 MOVWF ANRESL ; Store Low Byte (8 LSB bits) CALL IROUTPUT CALL ShortDelay RETURN USMEASUREMENT bcf T1CON,0 ; Disable TMR1 bcf PIR1,TMR1IF ; Clear Timer1 Overflow Flag & Timer1 Capture Flag bcf PIR1,CCP1IF clrf TMR1L ; Clear TMR1L clrf TMR1H ; Clear TMR1H clrf CCPR1L ; Clear CCPR1L clrf CCPR1H ; Clear CCPR1H call DEL_50 ; Wait 50 msec before enabling HW. bsf PORTC,0 ; Set INIT High on Ranging Module bsf T1CON,0 ; Enable TMR1 btfsc CheckMe,3 ; Check Short Range Condition call ShortRangeON ; call SBRT if set RETURN ShortRangeON call DEL_45 ; Delay 1,35 msec for transducer to stabilize call DEL_45 call DEL_45 bsf PORTC,5 ; Enable Transducer to Receive (BINH), to reduce internal blanking bsf SensorState,1 ; Short Range Operation is still ON return ShortRangeOFF bcf PORTC,5 ; Disable BINH bcf SensorState,1 ; No BIHN running anymore, until new communicaton return done call USOUTPUT bcf PORTC,0 ; Disable INIT btfsc SensorState,1 ; Have ShortRange Operation to be shutted OFF? call ShortRangeOFF bsf SensorState,0 ; Init disabled info RETURN ; **************************************************** ; * Interrupt Code * ; **************************************************** INTERRUPT movwf WREGsave ; Save WREG movf STATUS,W ; Get STATUS register movwf STATUSsave ; Save the STATUS register movf PCLATH,W ; Get PCLATH register movwf PCLATHsave ; Save PCLATH Bank0 ; select bank0 BSF PORTB,0 btfsc PIR1,SSPIF ; Is this a SSP interrupt? call SSP_Handler ; Yes, service SSP interrupt. btfsc PIR1,CCP1IF ; Is this a CCP1 interrupt? call CCP1_Handler ; Yes, service CCP1 interrupt. btfsc PIR1,TMR1IF ; Is this a TIMER1 interrupt? call TMR1_Handler ; Yes, service TIMER1 interrupt. BCF PORTB,0 RestoreAll movf PCLATHsave,W ; movwf PCLATH ; Restore PCLATH movf STATUSsave,W ; movwf STATUS ; Restore STATUS swapf WREGsave,F ; swapf WREGsave,W ; Restore WREG retfie ; Return from interrupt. ; **************************************************** ; * SSP Interrupt Code * ; **************************************************** SSP_Handler ; The I2C code below checks for 4 states: BSF STATUS,RP0 movf SSPSTAT,W ; Get the value of SSPSTAT andlw b'00100101' ; Mask out unimportant bits in SSPSTAT. BCF STATUS,RP0 ; Put masked value in Temp movwf Temp ; for comparision checking. ;State 1: I2C write operation, last byte was an address byte. movlw b'00000001' ; SSPSTAT bits: xorwf Temp,W ; D_A = 0, R_W = 0, BF = 1 btfsC STATUS,Z ; Are we in State1? goto State1 ; ;State 2: I2C write operation, last byte was a data byte. movlw b'00100001' ; SSPSTAT bits: xorwf Temp,W ; D_A = 1, R_W = 0, BF = 1 btfsC STATUS,Z ; Are we in State2? goto State2 ; No, check for next state..... ;State 3: I2C read operation, last byte was an address byte. movlw b'00000100' ; SSPSTAT bits: xorwf Temp,W ; D_A = 0, R_W = 1, BF = 0 btfsC STATUS,Z ; Are we in State3? goto State3 ; No, check for next state..... ;State 4: I2C read operation, last byte was a data byte. movlw b'00100100' ; SSPSTAT bits: xorwf Temp,W ; D_A = 1, R_W = 1, BF = 0 btfsC STATUS,Z ; Are we in State4? goto State4 ; No, check for next state.... Return State1: MOVLW B'00000001' MOVWF IndexRead ; Reset Index Read pointer MOVF SSPBUF,W ; Dummy read, address bcf PIR1,SSPIF ; Clear SSP Interrupt Flag bit RETURN State2: BCF STATUS,C RLF IndexRead,F ; Move index read pointer 1 left MOVF SSPBUF,W ; Get the byte and put in WREG BTFSC IndexRead,1 ; If readindex = 1 MOVWF WhatsNew ; then update commands with new data bcf PIR1,SSPIF ; Clear SSP Interrupt Flag bit RETURN State3: MOVLW B'00000001' MOVWF IndexWrite ; Reset Index Write pointer MOVF DataOutIR1Bis,W ; Keep High and Low Byte together MOVWF DataOutIR1 btfsc SensorState,0 ; Transmit US status to Master bsf DataOutIR1,6 MOVF DataOutIR2Bis,W ; Thus copy with interrupts disabled MOVWF DataOutIR2 MOVF DataOutUS1Bis,W ; Keep High and Low Byte together MOVWF DataOutUS1 andlw d'255' btfss STATUS,Z GOTO $+3 bsf DataOutUS1,7 ; May never be zero bsf DataOutIR1,5 ; Notify PC of change MOVF DataOutUS2Bis,W ; Thus copy with interrupts disabled MOVWF DataOutUS2 andlw d'255' btfss STATUS,Z GOTO $+3 bsf DataOutUS2,7 ; May never be zero bsf DataOutIR1,4 ; Notify PC of change State4: BCF STATUS,C RLF IndexWrite,F ; Move index write pointer 1 left BTFSC IndexWrite,1 ; If writeindex = 1 MOVF DataOutIR1,W ; then put DataOutIR1 into W BTFSC IndexWrite,2 ; If writeindex = 2 MOVF DataOutIR2,W ; then put DataOutIR2 into W BTFSC IndexWrite,3 ; If writeindex = 3 MOVF DataOutUS1,W ; then put DataOutUS1 into W BTFSC IndexWrite,4 ; If writeindex = 4 MOVF DataOutUS2,W ; then put DataOutUS2 into W BSF STATUS,RP0 BTFSC SSPSTAT,BF ; Is the buffer full? GOTO $-1 ; Yes, keep waiting. BCF STATUS,RP0 ; No, continue. DoI2CWrite BCF SSPCON,WCOL ; Clear the WCOL flag. MOVWF SSPBUF ; Write the byte in WREG BTFSC SSPCON,WCOL ; Was there a write collision? GOTO DoI2CWrite BSF SSPCON,CKP ; Release the clock. bcf PIR1,SSPIF ; Clear SSP Interrupt Flag bit RETURN ; **************************************************** ; * CCP1 Interrupt Code * ; **************************************************** CCP1_Handler chk_done ; Process the time capture bcf T1CON,0 ; Turn off TMR1 movf CCPR1L,W ; Move LSB into W movwf RESL ; Move LSB into RESL movf CCPR1H,W ; Move MSB into W movwf RESH ; Move MSB into RESH call done BCF PIR1,CCP1IF ; Clear Interrupt Flag RETURN ; **************************************************** ; * Timer1 Interrupt Code * ; **************************************************** TMR1_Handler ovr_flo bcf T1CON,0 ; Turn off TMR1 movlw D'255' movwf RESL movwf RESH call done BCF PIR1,TMR1IF RETURN ; **************************************************** ; * Setup SSP and enable interrupts * ; **************************************************** SetupSSP BCF STATUS,RP0 CLRF PIR1 ; clear all individual flag bits for peripheral interrupts CLRF SSPBUF MOVLW 0x36 ; Setup SSP module for 7-bit MOVWF SSPCON ; address, slave mode BSF STATUS,RP0 BSF TRISC,3 ; make RC3 and RC4 Inputs BSF TRISC,4 ; for SCL and SDA pins (Serial clock and Data) BCF STATUS,RP0 MOVF PORTB,W ; SWITCH port B ANDLW B'00111100' ; Save pins 5-2 BSF STATUS,RP0 MOVWF SSPADD ; Put W in I2C adress register BSF SSPADD,7 ; set bit 6 BCF STATUS,C ; RRF SSPADD,F ; Rotate 1 bit right; configure final address CLRF SSPSTAT BSF PIE1,SSPIE ; Enable periferal interrupts BCF STATUS,RP0 RETURN ; **************************************************** ; * Setup Analog routine: * ; **************************************************** SetupAnalog: BSF STATUS,RP0 MOVLW B'11001111' ; Right justified, AN0 analog input MOVWF ADCON1 ; AN2 = Vref- and AN3 = Vref+ clrf ADRESL ; Clear A/D Result Low BCF STATUS,RP0 MOVLW B'01000001' ; Conversion Clock Fosc/16 clrf ADRESH ; A/D converter powered-up MOVWF ADCON0 ; Clear A/D Result High RETURN ; **************************************************** ; * Setup Capture & Timer1: * ; **************************************************** SetupCCP: movlw b'00010000' ; TMR1 is off, Prescaler is 1:2 for a capture timeout movwf T1CON ; of 65'535 msec, about 11 m. movlw 0x05 movwf CCP1CON ; Set to capture on every rising edge clrf RESH ; Clear the result registers clrf RESL BSF STATUS,RP0 BSF PIE1,CCP1IE ; Enable interrupts BSF PIE1,TMR1IE BCF STATUS,RP0 RETURN ; **************************************************** ; * Enable All Interrupts routine: * ; **************************************************** EnableAllInt: BSF STATUS,RP0 BSF INTCON,PEIE ; Enable all peripheral interrupts BSF INTCON,GIE ; Enable global interrupts BCF STATUS,RP0 RETURN ; **************************************************** ; * Data processing * ; **************************************************** IROUTPUT: BCF STATUS,C RLF ANRESH,F ; Shift High byte 1 bit Left BTFSC ANRESL,7 BSF ANRESH,0 ; move 7th data bit to High byte, bit0 BSF ANRESH,7 ; Set 7th high, so result always <> 0 BSF ANRESL,7 ; Set 7th high, so result always <> 0 BSF STATUS,RP0 ; Bank 1 BCF INTCON,GIE ; Disable global interrupts BCF STATUS,RP0 ; Bank 0 MOVF ANRESH,W ; Keep High and Low Byte together MOVWF DataOutIR1Bis MOVF ANRESL,W ; Thus copy with interrupts disabled MOVWF DataOutIR2Bis BSF STATUS,RP0 ; Bank 1 BSF INTCON,GIE ; Enable global interrupts BCF STATUS,RP0 ; Bank 0 RETURN USOUTPUT: ; BSF STATUS,RP0 ; Bank 1 ; BCF INTCON,GIE ; Disable global interrupts ; BCF STATUS,RP0 ; Bank 0 MOVF RESH,W ; Keep High and Low Byte together MOVWF DataOutUS1Bis MOVF RESL,W ; Thus copy with interrupts disabled MOVWF DataOutUS2Bis ; BSF STATUS,RP0 ; Bank 1 ; BSF INTCON,GIE ; Enable global interrupts ; BCF STATUS,RP0 ; Bank 0 RETURN ; **************************************************** ; * Delays * ; **************************************************** DEL_45: movlw 0x02 ; Set Count2 for 0.45 msec delay movwf COUNT2 movlw 0xE0 ; Set Count1 for 0.45 msec delay movwf COUNT1 del_binh incfsz COUNT1, F ; Increase COUNT1 by 1 until zero (after h'FF') goto del_binh decfsz COUNT2, F ; Decrease COUNT2 by 1 until zero goto del_binh nop ; No Operation return DEL_50: movlw 0x82 ; Set Cnt2,Cnt1 for 50 msec delay movwf CNT2 clrf CNT1 del_low incfsz CNT1, F ; Increase CNT1 by 1 until zero (after h'FF') goto del_low decfsz CNT2, F ; Decrease CNT2 by 1 until zero goto del_low nop ; No Operation return DEL_75: movlw 0xC3 ; Set Count2,Count1 for 75 msec delay movwf CONT2 clrf CONT1 del_ag incfsz CONT1, F ; Increase CONT1 by 1 until zero (after h'FF') goto del_low decfsz CONT2, F ; Decrease CONT2 by 1 until zero goto del_ag nop ; No Operation return ShortDelay: MOVLW D'30' MOVWF TIMER1 DELAY2 MOVLW D'255' MOVWF TIMER2 DECFSZ TIMER2,F ; Decrease TIMER2 by 1 until zero GOTO $-1 DECFSZ TIMER1,F ; Decrease TIMER1 by 1 until zero GOTO DELAY2 RETLW 0 END ; End of file ; By Guillermo Moreno (thanx 2 RVH)