Steve - 2007-01-14

I managed to get this working with a 16F690 and a 24AA65 eeprom.  The 24AA65 takes a high address and an low address, so the eeprom read and write may have to be re-done to suit your particular eeprom.  I also had to back the delays off to 1ms.  The datasheet for the 24AA65 call for 5us delays, but I don't think my pic is that accurate. 

To use this, set these constants
#define I2CPORT PORTB
#define SDA_PORT 4
#define SCL_PORT 6
#define waittime 1 ms
#define chipwrite b'10100000'
#define chipread b'10100001'

i2c.h starts here
*****************************
'Subs
' eeprom_send(addrh,addrl,info)    Writes info to eeprom prom_addr and address addr
' eeprom_receive(addrh,addrl)    Reads from addrh and addrl

'Software I2C mode constants
#define I2CPORT PORTB
#define SDA_PORT 4
#define SCL_PORT 6
#define SDA I2CPORT.SDA_PORT
#define SCL I2CPORT.SCL_PORT
#define waittime 1 ms
#define chipwrite b'10100000'
#define chipread b'10100001'

sub ICC_initialize
ADOff 'make port digital
DIR I2CPORT b'00000000' 'make SCL and SDA outputs
DIR SDA OUT
DIR SCL OUT
SET SDA ON 'bring both SCL and SDA high
wait waittime
SET SCL ON
wait waittime
end sub

sub ICC_START
'subroutine to send start bit
DIR SDA OUT 'set SDA as output
wait waittime
SET SDA ON 'take SDA high
wait waittime
SET SCL ON 'take SCL high
wait waittime 'delay
SET SDA OFF 'take SDA low while clock high for start bit
wait waittime 'delay
SET SCL OFF 'take SCL low
end sub

sub ICC_stop
'subroutine to send a stop bit
SET SCL OFF
wait waittime
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low
SET SCL ON 'take SCL high
wait waittime 'delay 1 micro second
SET SDA ON 'take SDA high while SCL high for stop bit
wait waittime 'delay 5 micro second
end sub

sub ICC_send(XMIT)
'subroutine to send 8 bits
DIR SDA OUT 'set SDA as output
SET SCL OFF
wait waittime
for counter = 1 to 8
    SET SDA OFF 'clear SDA
    ROTATE XMIT LEFT 'if bit of XMIT is 1, set SDA
    IF STATUS.C ON THEN SET SDA ON
    SET SCL ON 'take SCL high
    wait waittime 'delay 5micro second
    SET SCL OFF 'take SCL low
    wait waittime
NEXT 'proceed with rest of bits in XMIT
'NOW acknowledge send
DIR SDA IN 'set SDA as input
SET SCL ON 'take SCL high
wait waittime 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime
DIR SDA OUT 'set SDA as output
end sub

function ICC_read
'subroutine to read a byte
'set SDA as input
DIR SDA IN
RX = 0
for counter = 1 to 8
    SET SCL ON 'take SCL high
    wait waittime
    SET STATUS.C OFF
    if SDA ON Then SET STATUS.C ON
    Rotate RX Left
    SET SCL OFF 'take SCL low
    wait waittime 'delay 5microseconds
NEXT 'do this for all 8 bits
ICC_read = RX
end function

sub ICC_send_ack
'subroutine to send the acknowledge bit
DIR SDA OUT 'set SDA as output
SET SDA OFF 'take SDA low
wait waittime 'delay 5microsends
SET SCL ON 'take SCL high
wait waittime 'delay 5microsends
SET SCL OFF 'take SCL low
wait waittime 'delay 5microsends
end sub

sub ICC_send_no_ack
'subroutine to send neg ack
DIR SDA OUT 'set SDA as output
SET SDA ON 'take SDA high
wait waittime 'delay 5microseconds
SET SCL ON 'take SCL high
wait waittime 'delay 5microseconds
SET SCL OFF 'take SCL low
wait waittime 'delay 5microseconds
end sub

sub eeprom_send(addr1,addr0,info)
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