Here's a more direct translation of the PIC code into the arduino environment. It hasn't been tested, or even compiled, but it should give you an idea of the way things are done. Note that this is not a particularly "efficient" method of implementing I2C on arduino; it's using Arduino primitives (digitalRead, etc) instead of direct port access, for instance. But the result is (hopefully) somewhat more understandable.
The code is made more difficult to understand because they have set up the I2C bus as an "open collector" bus; this allows it to be shared between multiple devices. But it means that each device can only write "zero" to the bus. To create a ONE state on the bus, the pin is turned into an input, and the external resistor you see on the OP-referenced web page "pulls up" the bus to the one state.) This means that instead of outputting ones and zeros (say, using digitalWrite), the code outputs a permanent zero and switches the pin from input (allows bus to go to 1 state) and output (zero goes out and pulls the bus low.) On the PIC, the "TRISxx" register bits control the direction of the corosponding data register bits. For example:
#define SCL TRISB4 // direction of pin B4, used as SCL
#define SCL_IN RB4 // Actual port pin B4 (SCL)
In the arduino environment, we'll use pinMode(), which is less obvious (the PIC code NAMES the direction register as if they were data bits, and the assignments happen to work out the same...) I'm not ENTIRELY sure that the pinMode functions, or the AVR pins, work exactly like this. I looked BRIEFLY, and I think it should be OK, but...) Here's what I came up with:
#define SCL_PIN 4 // Arduino pin number for SCL_IN
#define SDA_PIN 1 // Arduino pin number for SDA_IN
pinmode(SCL_PIN, INPUT); // Pins are inputs (floating) to allow
pinmode(SDA_PIN, INPUT); // other users on the bus.
digitalWrite(SCL_PIN, 0); // If they become outputs, we want a low
digitalWrite(SDA_PIN, 0); // level to be output.
void i2c_dly(void)
{
// a slight delay
}
// The following 4 functions provide the primitive
// start, stop, read and write sequences. All I2C
// transactions can be built up from these.
void i2c_start(void)
{
pinMode(SDA_PIN, INPUT); // i2c start bit sequence
i2c_dly();
pinMode(SCL_PIN, INPUT); // SDA, SCL == 1;
i2c_dly();
pinMode(SDA_PIN, OUTPUT); // Setting output causes 0
i2c_dly();
pinMode(SCL_PIN, OUTPUT);
i2c_dly();
}
void i2c_stop(void)
{
pinMode(SDA_PIN, OUTPUT); // i2c stop bit sequence
i2c_dly(); // output 0
pinMode(SCL_PIN, INPUT);
i2c_dly();
pinMode(SDA_PIN, INPUT);
i2c_dly();
}
unsigned char i2c_rx(char ack)
{
char x, d=0;
pinMode(SDA_PIN, INPUT); // = 1
for(x=0; x<8; x++) {
d <<= 1;
do {
pinMode(SCL_PIN, INPUT); // = 1
}
while(digitalRead(SCL_PIN)==0); // wait for any SCL clock stretching
i2c_dly();
if(digitalRead(SDA_PIN)) d |= 1;
pinMode(SCL_PIN, OUTPUT); // = 0
}
if(ack) pinMode(SDA_PIN, OUTPUT); // = 0
else pinMode(SDA_PIN, INPUT); // = 1
pinMode(SCL_PIN, INPUT); // = 1
i2c_dly(); // send (N)ACK bit
pinMode(SCL_PIN, OUTPUT); // = 0
pinMode(SDA_PIN, INPUT); // = 1
return d;
}
bit i2c_tx(unsigned char d)
{
char x;
static bit b;
for(x=8; x; x--) {
if(d&0x80) pinMode(SDA_PIN, INPUT); // = 1
else pinMode(SDA_PIN, OUTPUT); // = 0
pinMode(SCL_PIN, INPUT); // = 1
d <<= 1;
pinMode(SCL_PIN, OUTPUT); // = 0
}
pinMode(SDA_PIN, INPUT); // = 1
pinMode(SCL_PIN, INPUT); // = 1
i2c_dly();
b = digitalRead(SDA_PIN); // possible ACK bit
pinMode(SCL_PIN, OUTPUT); // = 0
return b;
}