Blame | Last modification | View Log | RSS feed
list p=16F84A
include "p16F84a.inc"
;***** CONFIGURATION
__CONFIG _PWRTE_ON & _HS_OSC & _WDT_OFF
; pin assignments
#define SDA 0 ; Pin 0
#define SCL 1 ; Pin 1
#define TRIS_SDA TRISB,SDA
#define TRIS_SCL TRISB,SCL
#define I2C_SDA PORTB,SDA
#define I2C_SCL PORTB,SCL
#define LED PORTB,2
#define I2C_SLAVE1 0x27
#define I2C_SLAVE2 0x26
CBLOCK 0CH
_I ; Loop counter
byte_send ; Byte to send to i2c
byte_read ; Byte read from i2c
byte_temp ; Store byte while address send
i2c_addr ; Address to read/write
i2c_ret ; I2C Return Value
dly_loop1 ; Loops for delays
dly_loop2
ENDC
ORG 0
goto start ; jump over to main routine
;***** Initialisation
start
; configure ports
clrw ; configure PORTB as all outputs
tris PORTB
clrf PORTB
movlw b'00001011' ; RA0 - Input - Toggle SW, Mode Select
; RA1 - Input - Pulse SW, Record
; RA2 - Output - LED, Mode
; RA3 - Input - Switch, Reset
tris PORTA
clrf byte_send
clrf byte_read
;***** Main loop
main_loop
bsf LED
call ReadByte ; Read byte from SLAVE2
bcf LED
movfw byte_read ; Copy the byte read
;movlw b'10101010'
movwf byte_send ; into the byte to send
call Delay_Short
bsf LED
call SendByte ; Send byte to SLAVE1
bcf LED
call Delay_Long
goto main_loop
ReadByte
movlw I2C_SLAVE2 ; Address of Slave2
movwf i2c_addr
bsf STATUS,C ; Set mode to read
call I2C_Start ; Send the address with mode
call ReadAck
;movf i2c_ret
;btfss STATUS,Z
;goto SendErr
call I2C_Read ; Read byte into byte_read
call ReadAck
call I2C_End
return
SendByte
movfw byte_send ; Save the byte while sending address
movwf byte_temp
movlw I2C_SLAVE1 ; 7-bit address of dev
movwf i2c_addr ; Set it in the address
bcf STATUS,C ; Use Write mode ('0')
call I2C_Start ; Start a transmission
call ReadAck ; Wait for Ack from slave
;movf i2c_ret ; Check return value
;btfss STATUS,Z ; Goto SendEnd on NACK
;goto SendErr
movfw byte_temp
movwf byte_send
;movfw byte_send ; Copy byte to write (counter) to w
call I2C_Write ; Write the byte to the line
call ReadAck ; Should read byte from bus here
; checking that its a Nack
call I2C_End ; End the packet
return
SendErr
call I2C_End
return
I2C_Start
rlf i2c_addr,f ; Attach mode (STATUS,C) to 1st bit
call Start ; Start the Trans
movfw i2c_addr
movwf byte_send ; Send the complete address
call I2C_Write ; Write byte to port
return
I2C_End
call Stop
return
I2C_Write
;movwf byte_send
movlw .8 ; 8 bits to send
movwf _I
_WriteBit
rlf byte_send,f ; Move highest bit to C
btfss STATUS,C ; If 'C' is clear
call SDA_Low ; -> Set data low
btfsc STATUS,C ; If 'C' is set
call SDA_High ; -> Set data high
call SCL_Pulse
decfsz _I,f ; Decrement counter, if not clear
goto _WriteBit ; -> Send next bit
call SDA_Low ; Set low to allow slave to write
return
I2C_Read
movlw .8 ; 8 bits to read
movwf _I
clrf byte_read ; Clear the read byte
bcf STATUS,C
call SDA_High ; Set high so slave can write
_ReadBit
call SCL_High ; Pull Clock high, bit should arrive
;btfss I2C_SDA ; If sda is clear
bcf STATUS,C ; -> Set status 0
btfsc I2C_SDA ; If sda is set
bsf STATUS,C
call SCL_Low ; Send the clock low
rlf byte_read,f ; Move highest bit to C
decfsz _I,f ; Decrement counter, if not clear
goto _ReadBit ; -> Send next bit
;call SDA_Low ; Set low to allow slave to write
return
Nack ; Clock a high SDA
call SDA_High
call SCL_Pulse
return
Ack ; Clock a high SDA
call SDA_Low
call SCL_Pulse
return
ReadAck
call SDA_High ; SDA high to allow slave to write
call SCL_High
clrf i2c_ret
btfsc I2C_SDA
bsf i2c_ret,0
call SCL_Low
return
Start
call SDA_High
call SCL_High
call SDA_Low
call SCL_Low
return
Stop ; Bring SDA high while Clock high
call SCL_Low
call SDA_Low
call SCL_High
call SDA_High
return
SCL_Pulse
call SCL_High
call SCL_Low
return
SDA_High
bsf STATUS,RP0 ; Bank 1
bsf TRIS_SDA ; Make SDA pin input
bcf STATUS,RP0 ; Back to bank 0
call Delay_Short
return
SDA_Low
bcf I2C_SDA
bsf STATUS,RP0
bcf TRIS_SDA ; Make SDA pin output
bcf STATUS,RP0
call Delay_Short
return
SCL_High
bsf STATUS,RP0 ; Bank 1
bsf TRIS_SCL ; Make SDA pin input
bcf STATUS,RP0 ; Back to bank 0
call Delay_Short
return
SCL_Low
bcf I2C_SCL
bsf STATUS,RP0
bcf TRIS_SCL ; Make SDA pin output
bcf STATUS,RP0
call Delay_Short
return
Delay_Short ; 25us delay
movlw .5
movwf dly_loop2
Delay_Short_1
nop
decfsz dly_loop2,f
goto Delay_Short_1
return
Delay_Long
movlw .250 ; 250ms delay
movwf dly_loop1
Outer
movlw .110 ; Close to 1ms when set to .110
movwf dly_loop2
Inner
nop
nop
nop
nop
nop
nop
decfsz dly_loop2,f
goto Inner
decfsz dly_loop1,f
goto Outer
return
END