I2C communication with external EEPROM via digital pins
Sometimes it may be convenient to use digital instead of analog pins for I2C communication, for example if you need to save analog pins for other purposes. After some detailed studies of the I2C protocol I wrote a code which enables any two digital pins to take over I2C communication, in this example with a 24lc256 EEPROM. The sketch shows how to write and to read a number to and from any address of the eeprom.
If you're using ARDUINO 1.0 then download the version at the bottom of this page. ARDUINO 1.0 uses a different syntax for activating internal pullups.
/*Example code for using two digital pins to establish I2C communication
with a 24LC256 EEPROM. Not to be used with Arduino 1.0
Written by Martin Thalheimer, 2011.
*/
byte data = 4; //digital pin 4 = data - connect to pin 5 of 24lc256
byte clock = 5; //digital pin 5 = clock - connect to pin 6 of 24lc256
int address=160; //address of the 24lc256 with all address pin tied to GND
int i2c_out;
int i;
int number=234; //put here a number of your choice (0-255) to be stored in the external eeprom
int memory_address=23456; /*put here the address of your choice (0-32767) within the eeprom where
you want the number to be stored*/
int adr_hi;
int adr_low;
void setup(){
Serial.begin(9600);
pinMode(clock, OUTPUT);
pinMode(data, OUTPUT);
}
void loop() {
Serial.println("writing...");
dig_eeprom_write(); //this function writes the number into the external eeprom
Serial.println(number);
Serial.print("to eeprom address ");
Serial.println(memory_address);
Serial.println("reading...");
dig_eeprom_read(); //this function reads the number from the external eeprom
Serial.println(i2c_out);
Serial.print("from eeprom address ");
Serial.println(memory_address);
Serial.println();
delay(2000);
}
void dig_eeprom_write() {
common_routine();
i2c_out=number;
putbyte(); //the number is being sent to the eeprom
getack(); //get acknowledge
Stop();
delay (100); //
}
void dig_eeprom_read() {
common_routine();
start();
i2c_out=address+1; //address of 24lc256 in read mode
putbyte(); //send byte
getack(); //get acknowledge
getbyte(); //retrieve content of the memory cell
givenoack(); //no acknowledge
Stop();
delay(10);
}
void common_routine () { //this part is common to each writing or reading cycle
start(); //start signal for eeprom to wake up
i2c_out=address; //address of 24lc256 in write mode
putbyte(); //send byte
getack(); //get acknowledge
adr_hi=memory_address/256; //
adr_low=memory_address % 256; //
i2c_out=adr_hi; //send the highbyte of the memory-address
putbyte(); //send byte
getack(); //get acknowledge
i2c_out=adr_low; //send the lowbyte of the memory-address
putbyte(); //send byte
getack(); //get acknowledge
}
void start() {
digitalWrite (clock, HIGH);
digitalWrite (data, HIGH);
digitalWrite (data, LOW);
digitalWrite (clock, LOW);
}
void putbyte() {
for (i=7; i>=0; i--){
if ((i2c_out &(1<<i))==0) {
digitalWrite (data, LOW);
}
else {
digitalWrite (data, HIGH);
}
digitalWrite (clock, HIGH); //pulse clock
digitalWrite (clock, LOW);
}
}
void getbyte() {
pinMode(data, INPUT);
i2c_out=0;
for (i=7; i>=0; i--){
if (digitalRead(data)==HIGH) {
i2c_out=(i2c_out + (1<<i));
delay(10);
}
digitalWrite (clock, HIGH); //pulse clock
digitalWrite (clock, LOW);
}
pinMode(data, OUTPUT);
}
void getack() {
digitalWrite (data, HIGH);
pinMode(data, INPUT);
digitalWrite (clock, HIGH);
digitalWrite (clock, LOW);
pinMode(data, OUTPUT);
}
void Stop() {
digitalWrite (data, LOW);
digitalWrite (clock, HIGH);
digitalWrite (data, HIGH);
}
void givenoack() {
digitalWrite (data, HIGH);
digitalWrite (clock, HIGH); //pulse clock
digitalWrite (clock, LOW);
digitalWrite (data, LOW);
}