Here is an I2C header file that worked for a 16f88 and a 24LC256 eeprom.
This a rejuggled Steve Bell library, only with pullups on the SDA and SCL lines. Also included are the required setup definitions and an example code. Please substitute whatever LCD methods you are using instead of my 'ascii' serial LCD.
Kent
Setup:
#include <I2CMstrSoftPullup.h> 'Or whatever you want to call it
#define SDA PortB.1 '16f88
#define SCL PortB.4 '16f88
#define waittime 1 ms
#define chipwrite b'10100000' '24lc256 address 1010+A2A1A0+R/W
#define chipread b'10100001'
Dim address as Word
Code:
Main:
LCD_Rst
address = 0
For logtemp = 0 to 255
address = address + 1
addrl = address
addrh = address_h
eeprom_send(addrh, addrl, logtemp)
wait 1 10ms 'Need some delay here for proper operation
Next
Do
address = 0
For count = 0 to 255
LCD_Rst
address = address + 1
addrl = address
addrh = address_h
ascii (eeprom_receive(addrh,addrl))
wait 1 s
Next
Loop
goto Main
Header file:
'==========================================================
'This is a Software Master I2C that uses pullups
'on the SDA and SCL lines. By Kent Schafer.
'This is a rejuggled Header file built by Steve Bell
'without pullups.
sub ICC_initialize 'Bus not Busy (A)Both SDA & SCL high
DIR SDA OUT
DIR SCL OUT
Dir SDA In 'SET SDA ON
Dir SCL In 'SET SCL ON
wait waittime
end sub
sub ICC_START 'Start Data Transfer (B) SDA high to low sequence while SCL high
Dir SDA In 'SET SDA ON
wait waittime
Dir SCL In 'SET SCL ON
wait waittime 'delay
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low while clock high for start bit
wait waittime 'delay
Dir SCL Out
SET SCL OFF 'take SCL low
end sub
sub ICC_stop 'Stop Data Transfer (C) A SDA low to high transition while SCL high
Dir SCL Out
SET SCL OFF
wait waittime
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low
Dir SCL In 'SET SCL ON
wait waittime
Dir SDA In 'SET SDA ON
wait waittime
end sub
sub ICC_send(XMIT) 'Data valid (D) data must be changed during SCL low cyle
Dir SCL Out
SET SCL OFF
wait waittime
for counter = 1 to 8
DIR SDA OUT 'set SDA as output
SET SDA OFF 'clear SDA
ROTATE XMIT LEFT 'if bit of XMIT is 1, set SDA
IF STATUS.C ON THEN Dir SDA In 'SET SDA ON
Dir SCL In 'SET SCL ON 'take SCL high
wait waittime
Dir SCL Out
SET SCL OFF 'take SCL low
wait waittime
NEXT 'proceed with rest of bits in XMIT
'NOW each receiving device must acknowledge after each byte sent
DIR SDA IN 'set SDA as input
Dir SCL In 'SET SCL ON'take SCL high
wait waittime
Dir SCL Out
SET SCL OFF 'take SCL low
wait waittime
DIR SDA OUT 'set SDA as output
end sub
function ICC_read
DIR SDA IN
RX = 0
for counter = 1 to 8
Dir SCL In 'SET SCL ON
wait waittime
SET STATUS.C OFF
if SDA ON Then SET STATUS.C ON
Rotate RX Left
Dir SCL Out
SET SCL OFF 'take SCL low
wait waittime
NEXT 'do this for all 8 bits
ICC_read = RX
End function
sub ICC_send_no_ack 'SDA must be left Hi-Z after an EEPROM read
Dir SDA In
wait waittime
Dir SCL In 'SET SCL ON
wait waittime
Dir SCL Out
SET SCL OFF 'take SCL low
wait waittime
end sub
sub eeprom_send(addr1,addr0,info)#NR
DIR SDA OUT 'set SCL and SDA as outputs
DIR SCL OUT
ICC_initialize 'call init and start subroutine
ICC_START
ICC_send(chipwrite) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_send(info) 'send data
ICC_STOP 'call stop subroutine
end sub
Function eeprom_receive(addr1,addr0)
DIR SDA OUT 'set SCL and SDA as outputs
DIR SCL OUT
ICC_initialize 'call init and start subroutine
ICC_START
ICC_send(chipwrite) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_STOP
ICC_START
ICC_send(chipread) 'send prom_addr for read
eeprom_receive = ICC_read 'call subroutine read
ICC_send_no_ack 'call subroutine no_ack
DIR SDA OUT
ICC_STOP
end function
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Here is an I2C header file that worked for a 16f88 and a 24LC256 eeprom.
This a rejuggled Steve Bell library, only with pullups on the SDA and SCL lines. Also included are the required setup definitions and an example code. Please substitute whatever LCD methods you are using instead of my 'ascii' serial LCD.
Kent
Setup:
#include <I2CMstrSoftPullup.h> 'Or whatever you want to call it
#define SDA PortB.1 '16f88
#define SCL PortB.4 '16f88
#define waittime 1 ms
#define chipwrite b'10100000' '24lc256 address 1010+A2A1A0+R/W
#define chipread b'10100001'
Dim address as Word
Code:
Main:
LCD_Rst
address = 0
For logtemp = 0 to 255
address = address + 1
addrl = address
addrh = address_h
eeprom_send(addrh, addrl, logtemp)
wait 1 10ms 'Need some delay here for proper operation
Next
Do
address = 0
For count = 0 to 255
LCD_Rst
address = address + 1
addrl = address
addrh = address_h
ascii (eeprom_receive(addrh,addrl))
wait 1 s
Next
Loop
goto Main
Header file:
'==========================================================
'This is a Software Master I2C that uses pullups
'on the SDA and SCL lines. By Kent Schafer.
'This is a rejuggled Header file built by Steve Bell
'without pullups.
sub ICC_initialize 'Bus not Busy (A)Both SDA & SCL high
DIR SDA OUT
DIR SCL OUT
Dir SDA In 'SET SDA ON
Dir SCL In 'SET SCL ON
wait waittime
end sub
sub ICC_START 'Start Data Transfer (B) SDA high to low sequence while SCL high
Dir SDA In 'SET SDA ON
wait waittime
Dir SCL In 'SET SCL ON
wait waittime 'delay
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low while clock high for start bit
wait waittime 'delay
Dir SCL Out
SET SCL OFF 'take SCL low
end sub
sub ICC_stop 'Stop Data Transfer (C) A SDA low to high transition while SCL high
Dir SCL Out
SET SCL OFF
wait waittime
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low
Dir SCL In 'SET SCL ON
wait waittime
Dir SDA In 'SET SDA ON
wait waittime
end sub
sub ICC_send(XMIT) 'Data valid (D) data must be changed during SCL low cyle
Dir SCL Out
SET SCL OFF
wait waittime
for counter = 1 to 8
DIR SDA OUT 'set SDA as output
SET SDA OFF 'clear SDA
ROTATE XMIT LEFT 'if bit of XMIT is 1, set SDA
IF STATUS.C ON THEN Dir SDA In 'SET SDA ON
Dir SCL In 'SET SCL ON 'take SCL high
wait waittime
Dir SCL Out
SET SCL OFF 'take SCL low
wait waittime
NEXT 'proceed with rest of bits in XMIT
'NOW each receiving device must acknowledge after each byte sent
DIR SDA IN 'set SDA as input
Dir SCL In 'SET SCL ON'take SCL high
wait waittime
Dir SCL Out
SET SCL OFF 'take SCL low
wait waittime
DIR SDA OUT 'set SDA as output
end sub
function ICC_read
DIR SDA IN
RX = 0
for counter = 1 to 8
Dir SCL In 'SET SCL ON
wait waittime
SET STATUS.C OFF
if SDA ON Then SET STATUS.C ON
Rotate RX Left
Dir SCL Out
SET SCL OFF 'take SCL low
wait waittime
NEXT 'do this for all 8 bits
ICC_read = RX
End function
sub ICC_send_no_ack 'SDA must be left Hi-Z after an EEPROM read
Dir SDA In
wait waittime
Dir SCL In 'SET SCL ON
wait waittime
Dir SCL Out
SET SCL OFF 'take SCL low
wait waittime
end sub
sub eeprom_send(addr1,addr0,info)#NR
DIR SDA OUT 'set SCL and SDA as outputs
DIR SCL OUT
ICC_initialize 'call init and start subroutine
ICC_START
ICC_send(chipwrite) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_send(info) 'send data
ICC_STOP 'call stop subroutine
end sub
Function eeprom_receive(addr1,addr0)
DIR SDA OUT 'set SCL and SDA as outputs
DIR SCL OUT
ICC_initialize 'call init and start subroutine
ICC_START
ICC_send(chipwrite) 'send prom_addr
ICC_send(addr1) 'send high memory addr
ICC_send(addr0) 'send low memory addr
ICC_STOP
ICC_START
ICC_send(chipread) 'send prom_addr for read
eeprom_receive = ICC_read 'call subroutine read
ICC_send_no_ack 'call subroutine no_ack
DIR SDA OUT
ICC_STOP
end function
PS: Make Main an open loop at end of example code, otherwise, it will eventually wear out the eeprom by continuously writing to it.