InitI2CBusMaster
;************************************************************
TxmtStartBit
bsf Bus_Busy ; on a start condition bus is busy
bsf STATUS, RP0 ; Select page 1
bsf _SDA ; set SDA high
bsf _SCL ; clock is high
call Delay40uSec ; This is necessary for setup time
bcf _SDA ; This gives a falling edge on SDA while clock is high
call Delay47uSec ; Necessary for START HOLD time
return
;************************************************************
TxmtStopBit
bsf STATUS, RP0 ; Select page 1
bcf _SCL ; clock is low
bcf _SDA ; set SDA low
bsf _SCL ; clock is pulled up
call Delay40uSec ; Setup time for STOP condition
bsf _SDA ; rising edge on SDA while CLOCK is high
call Delay47uSec ; makes sure a START isn't sent immediately after a STOP
bcf Bus_Busy ; The bus isn't busy anymore
return
;************************************************************
AbortI2C
call TxmtStopBit ; Send a stop bit
bsf Abort ; set the abort bit
return
;************************************************************
TxmtSlaveAddr
movf SlaveAddr, w ; Move slave address to W
bcf ACK_Error ; reset Acknowledge error bit
movwf I2CData ; move W to I2C Data
bcf I2CData, LSB ; Set for write
btfsc Slave_RW ; If skip then write operation
bsf I2CData, LSB ; Clear for read
call SendData ; send the address
btfss Txmt_Success ; skip if successful
goto AddrSendFail ; Oops, we failed
retlw TRUE ; return true
AddrSendFail
btfss ACK_Error ; was there an error acknowledging
retlw FALSE ; No, so return 0
call TxmtStopBit ; Address not acknowleged, so send STOP bit
retlw FALSE ; Unsuccessful, so return 0
;************************************************************
SendData
; We might should make a copy of the data here, the example does but I don't see why!!!
bsf Txmt_Progress ; We are in the middle of transmitting
bcf Txmt_Success ; reset success bit
movlw 0x08
movwf I2CBitCount ; Set I2C Bit Count to 8
bsf STATUS, RP0 ; Select page 1
TxmtNextBit:
bcf _SCL ; Set clock Low
rlf I2CData, F ; MSB First, Note that I2CData is Destroyed
bcf _SDA ; Set clock based on what the MSB is
btfsc STATUS,C ; Was the MSB a 1
bsf _SDA ; Nope set it high
call Delay47uSec ; guarantee min LOW TIME tLOW & Setup time
bsf _SCL ; set clock high
call Delay40uSec ; guarantee min HIGH TIME tHIGH
decfsz I2CBitCount, F ; are we done yet
goto TxmtNextBit ; nope, send the next bit
;
; Check For Acknowledge
;
bcf _SCL ; reset clock
bsf _SDA ; Release SDA line for Slave to pull down
call Delay47uSec ; guarantee min LOW TIME tLOW & Setup time
bsf _SCL ; clock for slave to ACK
call Delay40uSec ; guarantee min HIGH TIME tHIGH
bcf STATUS, RP0 ; Select PAGE 0 to test SDA pin
btfsc SdaPin ; SDA should be pulled low by slave if OK
goto TxmtErrorAck ; Uh oh, slave isn't behaving (or isn't there)
bsf STATUS, RP0 ; Select PAGE 1
bcf _SCL ; reset clock
bcf Txmt_Progress ; reset progress bit in Bus Status
bsf Txmt_Success ; Transmission successful
bcf ACK_Error ; ACK OK
return
TxmtErrorAck
bsf STATUS,RP0 ; select page 1
bsf _SDA ; tristate SDA
bsf _SCL ; tristate SCL
bcf Txmt_Progress ; reset progress bit in Bus Status
bcf Txmt_Success ; Transmission NOT successful
bsf ACK_Error ; No ACK From Slave
return
;************************************************************
GetData
bsf Rcv_Progress ; set Bus status for txmt progress
bcf Rcv_Success ; reset status bit
movlw 0x08
movwf I2CBitCount
RcvNextBit
bsf STATUS, RP0 ; page 1 for TRIS manipulation
bcf _SCL ; lower clock
bcf _SDA ; lower data line
call Delay47uSec ; guarantee min LOW TIME tLOW & setup time
bsf _SCL ; clock high, data sent by slave
call Delay40uSec ; guarantee min HIGH TIME tHIGH
bcf STATUS, RP0 ; select page 0 to read Ports
bcf STATUS, C ; 0 out Status
btfsc SdaPin ; Check state of pin
bsf STATUS, C ; Pin was high, set status
rlf I2CData, F ; left Shift data (MSB first)
decfsz I2CBitCount, F ; Are we done yet
goto RcvNextBit ; Nope, go get the next one
;
; Generate ACK bit if not last byte to be read,
; if last byte Gennerate NACK ; do not send ACK on last byte, main routine will send a STOP bit
;
bsf STATUS, RP0 ; Page 1 for TRIS manipulation
bcf _SCL ; pull SCL low
bcf _SDA ; ACK by pulling SDA low
btfsc Last_Byte_Rcv ; Is it the last byte to receive
bsf _SDA ; If so, send NACK by setting SDA high
call Delay47uSec ; guarantee min LOW TIME tLOW & Setup time
bsf _SCL ; Raise Clock back up
call Delay40uSec ; guarantee min HIGH TIME tHIGH
RcvEnd:
bcf _SCL ; reset clock
bcf Rcv_Progress ; reset bit in Bus Status
bsf Rcv_Success ; transmission successful
bcf ACK_Error ; ACK OK
return
Delay47uSec:
movlw ((_47uS_Delay-5)/3 + 1) ; move delay into W
DlyK
movwf DelayCount ; move what is in W to DelayCount
decfsz DelayCount, F ; Decrement DelayCount
goto $-1 ; Loop until 0
return ; return
Delay40uSec:
movlw ((_40uS_Delay-8)/3 + 1) ; move delay into W
goto DlyK ; goto DlyK loop
评论
查看更多