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);

     }