#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' DataOutIR3 EQU H'4C' DataOutIR4 EQU H'4D' DataOutIR1Bis EQU H'4E' DataOutIR2Bis EQU H'4F' DataOutIR3Bis EQU H'50' DataOutIR4Bis 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 CheckMe EQU H'25' ;Check Measurement CNT1 EQU H'26' ;Temporary count register CNT2 EQU H'27' ;Temporary count register TIMER1 EQU H'2A' ;Temporary count register TIMER2 EQU H'2B' ;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 DataOutIR3Bis clrf DataOutIR4Bis ;****************** ; Bank 1 Registers ;****************** ; Set RP0 bsf STATUS,RP0 ; Configure PORTA: IR signal (RA0, RA1) as an input as well as Vref+ and Vref- ; (RA3, RA2) MOVLW B'00001111' MOVWF TRISA MOVLW B'00111110' MOVWF TRISB movlw B'00000000' movwf TRISC bcf STATUS,RP0 ; Clear RP0 ; Initial conditions MOVLW B'00010000' ; STOP signal, ALL measuring MOVWF WhatsNew clrf DataOutIR1Bis clrf DataOutIR2Bis clrf DataOutIR3Bis clrf DataOutIR4Bis CALL SetupSSP ; Initialise I2C Communication CALL SetupAnalog ; Initialise Analog Input PortA0 CALL EnableAllInt ; Start Interrupts call DEL_50 ; Delay 50 ms MAINLOOP BCF PORTC,6 BCF PORTC,7 BTFSC WhatsNew,6 ; Reset? GOTO RESET BTFSS WhatsNew,7 ; Wait? GOTO MAINLOOP MOVF WhatsNew,W MOVWF CheckMe BTFSS CheckMe,4 ; IR? GOTO MAINLOOP IRAction1 BSF PORTC,6 ; Switch Led On BCF ADCON0,CHS0 ; AN0 as A/D input CALL IRMEASUREMENT ; AD conv CALL IROUTPUT1 ; Store digital value IR 1 CALL ShortDelay IRAction2 BCF PORTC,6 ; Switch Led Off BSF PORTC,7 ; Switch Led On BSF ADCON0,CHS0 ; AN1 as A/D input CALL IRMEASUREMENT ; AD conv CALL IROUTPUT2 ; Store digital value IR 2 CALL ShortDelay GOTO MAINLOOP ; Loop main program ; **************************************************** ; * Measurement loops * ; **************************************************** IRMEASUREMENT ; clrf ANRESH ; clear storage Analog value MSByte ; clrf ANRESL ; clear storage Analog value LSByte 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 CLRF ADRESH ; clear High Byte BSF STATUS,RP0 MOVF ADRESL,W ; Read Low Byte : Bank 1 CLRF ADRESL ; clear Low Byte BCF STATUS,RP0 MOVWF ANRESL ; Store Low Byte (8 LSB bits) 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 bcf STATUS,RP0 ; select bank0 BSF PORTB,0 ; Switch Led On btfsc PIR1,SSPIF ; Is this a SSP interrupt? call SSP_Handler ; Yes, service SSP interrupt. BCF PORTB,0 ; Switch Led Off 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 MOVF DataOutIR2Bis,W ; Thus copy with interrupts disabled MOVWF DataOutIR2 MOVF DataOutIR3Bis,W ; Keep High and Low Byte together MOVWF DataOutIR3 MOVF DataOutIR4Bis,W ; Thus copy with interrupts disabled MOVWF DataOutIR4 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 DataOutIR3,W ; then put DataOutIR3 into W BTFSC IndexWrite,4 ; If writeindex = 4 MOVF DataOutIR4,W ; then put DataOutIR4 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 ; **************************************************** ; * 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 address, slave mode MOVWF SSPCON ; Enables serial port, 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'11001101' ; Right justified, AN1 and 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 MOVWF ADCON0 ; A/D converter powered-up clrf ADRESH ; Clear A/D Result High 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 * ; **************************************************** IROUTPUT1: 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 IROUTPUT2: 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 DataOutIR3Bis MOVF ANRESL,W ; Thus copy with interrupts disabled MOVWF DataOutIR4Bis BSF STATUS,RP0 ; Bank 1 BSF INTCON,GIE ; Enable global interrupts BCF STATUS,RP0 ; Bank 0 RETURN ; **************************************************** ; * Delays * ; **************************************************** 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 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)