/* Title: I2C_Master_Software_0.ino Author: Florin Dragan florind@mas.utcluj.ro Date Created: 01-10-2017 Last Modified: 02-03-2020 Purpose: This is an example how to use I2C interface with Software implementation */ #define SDA_Pin 2 //PD2 #define SCL_Pin 3 //PD3 /* Defining the pin state as macros*/ #define SDA_HIGH digitalWrite(SDA_Pin, 1) #define SDA_LOW digitalWrite(SDA_Pin, 0) #define SCL_HIGH digitalWrite(SCL_Pin, 1) #define SCL_LOW digitalWrite(SCL_Pin, 0) /* Set INITIAL (pause) state condition */ void I2CInit() { SDA_HIGH; SCL_HIGH; } /* Set START condition */ void I2CStart() { SDA_LOW; SCL_LOW; } /* Set RESTART condition */ void I2CRestart() { SDA_HIGH; SCL_HIGH; SDA_LOW; SCL_LOW; } /* Set STOP condition */ void I2CStop() { SCL_LOW; SDA_LOW; SCL_HIGH; SDA_HIGH; } /* Set ACK condition */ void I2CAck() { SDA_LOW; SCL_HIGH; SCL_LOW; SDA_HIGH; } /* Set NACK condition */ void I2CNak() { SDA_HIGH; SCL_HIGH; SCL_LOW; SDA_HIGH; } /* Send a byte (8 bit in length) to I2C Slave */ unsigned char I2CSend(unsigned char Data) { unsigned char i, ack_bit; for (i = 0; i < 8; i++) { if ((Data & 0x80) == 0) { SDA_LOW; } else { SDA_HIGH; } /* Pulse clock signal */ SCL_HIGH; SCL_LOW; /* Data displacement one bit left */ Data<<=1; } //end for /* Verify (read) Slave ACK */ SDA_HIGH; SCL_HIGH; ack_bit = digitalRead(SDA_Pin); SCL_LOW; return ack_bit; } //end Send /* Read a byte (8 bit in length) from I2C Slave */ unsigned char I2CRead() { unsigned char i, Data=0; for (i = 0; i < 8; i++) { /* Rise clock signal and read SDA status */ SCL_HIGH; if(digitalRead(SDA_Pin)) Data |=1; if(i<7) Data<<=1; /* Lower the clock signal level */ SCL_LOW; } //end for return Data; } int main(void) { /* How to use functions above examples */ unsigned char ack, data[3]; /***************************************** * Write to slave device with * slave address e.g. say 0x20 |write bit = 0 *****************************************/ /* Init i2c ports first */ I2CInit(); /* Send start condition */ I2CStart(); /* Send slave address */ ack = I2CSend(0x20); /* * ack == 1 => NAK * ack == 0 => ACK */ /* Send register address (pointer) to write to*/ ack = I2CSend(0x07); /* Send data and store ack status value */ ack = I2CSend(0x10); /* Send stop condition to end transmission */ I2CStop(); /***************************************** * Read from slave device with * slave address e.g. say 0x20 *****************************************/ /* Init i2c ports first - Should be done ONCE in main */ I2CInit(); /* Send start condition */ I2CStart(); /* * Send slave address with Read bit = 1 * So address is 0x20 | 1 = 0x21 */ I2CSend(0x21); /* Read first byte */ data[0] = I2CRead(); /* Send ack */ I2CAck(); /* Read last byte */ data[1] = I2CRead(); /* and so on .... * Send nak for last byte to indicate * End of transmission */ I2CNak(); /* Send stop condition to end transmission */ I2CStop(); } //end main