Blame | Last modification | View Log | RSS feed
list p=16F88#include <p16f88.inc> ; Change to device that you are using.__CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_ON & _HS_OSCERRORLEVEL -302;---------------------------------------------------------------------;Constant Definitions;---------------------------------------------------------------------#define NODE_ADDR 0x4e ; I2C address of this node; Change this value to address that; you wish to use.;---------------------------------------------------------------------; Buffer Length Definition;---------------------------------------------------------------------#define RX_BUF_LEN 8 ; Length of receive buffer;---------------------------------------------------------------------; Variable declarations;---------------------------------------------------------------------udata_shrWREGsave res 1udataSTATUSsave res 1FSRsave res 1PCLATHsave res 1Index res 1 ; Index to receive bufferTemp res 1 ;RXBuffer res RX_BUF_LEN ; Holds rec'd bytes from master; device.;---------------------------------------------------------------------; Vectors;---------------------------------------------------------------------STARTUP code 0x00nopgoto Startup ;nop ; 0x0002nop ; 0x0003goto ISR ; 0x0004PROG code;---------------------------------------------------------------------; Macros;---------------------------------------------------------------------memset macro Buf_addr,Value,Lengthmovlw Length ; This macro loads a range of data memorymovwf Temp ; with a specified value. The startingmovlw Buf_addr ; address and number of bytes are alsomovwf FSR ; specified.SetNext movlw Valuemovwf INDFincf FSR,Fdecfsz Temp,Fgoto SetNextendmLFSR macro Address,Offset ; This macro loads the correct valuemovlw Address ; into the FSR given an initial datamovwf FSR ; memory address and offset value.movf Offset,Waddwf FSR,Fendm;---------------------------------------------------------------------; Main Code;---------------------------------------------------------------------Startupbcf STATUS,RP1bsf STATUS,RP0call Setupbanksel WREGsaveMain clrwdt ; Clear the watchdog timer.btfsc RXBuffer,7bsf PORTB,2btfss RXBuffer,7bcf PORTB,2goto Main ; Loop forever.;---------------------------------------------------------------------; Interrupt Code;---------------------------------------------------------------------ISRmovwf WREGsave ; Save WREGmovf STATUS,W ; Get STATUS registerbanksel STATUSsave ; Switch banks, if needed.movwf STATUSsave ; Save the STATUS registermovf PCLATH,W ;movwf PCLATHsave ; Save PCLATHmovf FSR,W ;movwf FSRsave ; Save FSRbanksel PIR1btfss PIR1,SSPIF ; Is this a SSP interrupt?goto $ ; No, just trap here.bcf PIR1,SSPIFcall SSP_Handler ; Yes, service SSP interrupt.banksel FSRsavemovf FSRsave,W ;movwf FSR ; Restore FSRmovf PCLATHsave,W;movwf PCLATH ; Restore PCLATHmovf STATUSsave,W;movwf STATUS ; Restore STATUSswapf WREGsave,F ;swapf WREGsave,W ; Restore WREGretfie ; Return from interrupt.;---------------------------------------------------------------------Setup;; Initializes program variables and peripheral registers.;---------------------------------------------------------------------banksel PCONbsf PCON,NOT_PORbsf PCON,NOT_BORbanksel ANSELmovlw 0x00movwf ANSELbanksel Index ; Clear various program variablesclrf Indexclrf PORTBclrf PIR1banksel TRISB;clrf TRISBbsf TRISB,4bsf TRISB,6bsf TRISB,1bcf TRISB,2movlw 0x36 ; Setup SSP module for 7-bitbanksel SSPCONmovwf SSPCON ; address, slave modemovlw NODE_ADDRbanksel SSPADDmovwf SSPADDclrf SSPSTATbanksel PIE1 ; Enable interruptsbsf PIE1,SSPIEbsf INTCON,PEIE ; Enable all peripheral interruptsbsf INTCON,GIE ; Enable global interruptsbcf STATUS,RP0return;---------------------------------------------------------------------SSP_Handler;---------------------------------------------------------------------; The I2C code below checks for 5 states:;---------------------------------------------------------------------; State 1: I2C write operation, last byte was an address byte.; SSPSTAT bits: S = 1, D_A = 0, R_W = 0, BF = 1;; State 2: I2C write operation, last byte was a data byte.; SSPSTAT bits: S = 1, D_A = 1, R_W = 0, BF = 1;; State 3: I2C read operation, last byte was an address byte.; SSPSTAT bits: S = 1, D_A = 0, R_W = 1 (see Appendix C for more information);; State 4: I2C read operation, last byte was a data byte.; SSPSTAT bits: S = 1, D_A = 1, R_W = 1, BF = 0;; State 5: Slave I2C logic reset by NACK from master.; SSPSTAT bits: S = 1, D_A = 1, BF = 0 (see Appendix C for more information);; For convenience, WriteI2C and ReadI2C functions have been used.;----------------------------------------------------------------------banksel SSPSTATmovf SSPSTAT,W ; Get the value of SSPSTATandlw b'00101101' ; Mask out unimportant bits in SSPSTAT.banksel Temp ; Put masked value in Tempmovwf Temp ; for comparision checking.State1: ; Write operation, last byte was anmovlw b'00001001' ; address, buffer is full.xorwf Temp,W ;btfss STATUS,Z ; Are we in State1?goto State2 ; No, check for next state.....memset RXBuffer,0,RX_BUF_LEN ; Clear the receive buffer.clrf Index ; Clear the buffer index.banksel SSPBUF ; Do a dummy read of the SSPBUF.movf SSPBUF,WreturnState2: ; Write operation, last byte was data,movlw b'00101001' ; buffer is full.xorwf Temp,Wbtfss STATUS,Z ; Are we in State2?goto State3 ; No, check for next state.....LFSR RXBuffer,Index ; Point to the buffer.banksel SSPBUF ; Get the byte from the SSP.movf SSPBUF,Wmovwf INDF ; Put it in the buffer.incf Index,F ; Increment the buffer pointer.movf Index,W ; Get the current buffer index.sublw RX_BUF_LEN ; Subtract the buffer length.btfsc STATUS,Z ; Has the index exceeded the buffer length?clrf Index ; Yes, clear the buffer index.returnState3: ; Read operation, last byte was an address,movf Temp,W ;andlw b'00101100' ; Mask BF bit in SSPSTATxorlw b'00001100'btfss STATUS,Z ; Are we in State3?goto State4 ; No, check for next state.....clrf Index ; Clear the buffer index.LFSR RXBuffer,Index ; Point to the buffermovf INDF,W ; Get the byte from buffer.call WriteI2C ; Write the byte to SSPBUFincf Index,F ; Increment the buffer index.returnState4: ; Read operation, last byte was data,banksel SSPCON ; buffer is empty.btfsc SSPCON, CKPgoto State5movlw b'00101100'xorwf Temp,Wbtfss STATUS,Z ; Are we in State4?goto State5 ; No, check for next state....movf Index,W ; Get the current buffer index.sublw RX_BUF_LEN ; Subtract the buffer length.btfsc STATUS,Z ; Has the index exceeded the buffer length?clrf Index ; Yes, clear the buffer index.LFSR RXBuffer,Index ; Point to the buffermovf INDF,W ; Get the bytecall WriteI2C ; Write to SSPBUFincf Index,F ; Increment the buffer index.returnState5:movf Temp,W ; NACK received when sending data to the masterandlw b'00101000' ; Mask RW bit in SSPSTATxorlw b'00101000' ;btfss STATUS,Z ;goto I2CErr ;return ; If we aren’t in State5, then something is; wrong.I2CErr nopbanksel PORTB ; Something went wrong! Set LEDbsf PORTB,2 ; and loop forever. WDT will resetgoto $ ; device, if enabled.return;---------------------------------------------------------------------; WriteI2C;---------------------------------------------------------------------WriteI2Cbanksel SSPSTATbtfsc SSPSTAT,BF ; Is the buffer full?goto WriteI2C ; Yes, keep waiting.banksel SSPCON ; No, continue.DoI2CWritebcf SSPCON,WCOL ; Clear the WCOL flag.movwf SSPBUF ; Write the byte in WREGbtfsc SSPCON,WCOL ; Was there a write collision?goto DoI2CWritebsf SSPCON,CKP ; Release the clock.returnend