A comunicação de dados por I2C tem caracteristicas que o tornam muito usado na comunicação com vários dispositivos electrónicos usados nos projectos com microcontroladores, incluindo o Arduino.
Do ponto de vista das ligações o interface I2C é simples e facil de implementar. Para funcionar, o I2C precisa apenas de duas linhas (dois pinos no Arduino) a SDA e a SCL, que são o bus do I2C, e duas resistências a fazer de pull up nas linhas, ás quais se podem ligar vários dispositivos com interface I2C.

No caso dos Arduinos, como estes pinos já tem os pull up internamente, não é necessário colocar as resistencias entre as linhas e o vcc. No entanto, como todos os Arduinos tem esses pull ups, pelo que percebi, significa que o número de Arduinos possiveis de ligar é mais limitado que o maximo teórico.
Os dispositivos ligados ao bus I2C podem ser de dois tipos diferentes:
- Master
- Slave
A principal e mais notória diferença é que só os masters podem iniciar comunicações.
O bus I2C do Arduino pode ser explorado nos seguintes ambientes:
- Unico master i2C
- Multiplos masters no bus I2C
- Multiplos Bus I2C
De todos os ambientes o menos problemático é o ambiente de unico master.
Estou a efectuar vários testes relacionados com a exploração estável das comunicações I2C.
Nota: Só transmite bytes e um limite de 32 bytes por comunicação.
Bibliotecas
Lista de bibliotecas
https://github.com/Testato/SoftwareWire/wiki/Arduino-I2C-libraries
Wire
https://www.arduino.cc/en/Reference/Wire
Alternativas (apenas master)
SoftI2CMaster & SlowSoftI2CMaster
https://playground.arduino.cc/Main/SoftwareI2CLibrary
https://github.com/felias-fogg/SoftI2CMaster
https://github.com/felias-fogg/SlowSoftI2CMaster
Alternativas (slave)
https://github.com/cirthix/SoftIIC
https://github.com/rambo/TinyWire
Formas de passar os dados numéricos por I2C
Como caracteres ascii
Passar os dados numéricos como strings. Implica a conversão do formato numérico para string.
Forma encontrada no seguinte link:
https://arduino.stackexchange.com/questions/16292/sending-and-receiving-different-types-of-data-via-i2c-in-arduino
Master
//master
#include <Wire.h>
char t[10]={};//empty array where to put the numbers comming from the slave
volatile int Val; // varaible used by the master to sent data to the slave
void setup() {
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}
void loop() {
Wire.requestFrom(8, 3); // request 3 bytes from slave device #8
//gathers data comming from slave
int i=0; //counter for each bite as it arrives
while (Wire.available()) {
t[i] = Wire.read(); // every character that arrives it put in order in the empty array "t"
i=i+1;
}
Serial.println(t); //shows the data in the array t
delay(500); //give some time to relax
// send data to slave. here I am just sending the number 2
Val=2;
Wire.beginTransmission (8);
Wire.write (Val);
Wire.endTransmission ();
}
Slave
#include <Wire.h>
char t[10]; //empty array where to put the numbers going to the master
volatile int Val; // variable used by the master to sent data to the slave
void setup() {
Wire.begin(8); // Slave id #8
Wire.onRequest(requestEvent); // fucntion to run when asking for data
Wire.onReceive(receiveEvent); // what to do when receiving data
Serial.begin(9600); // serial for displaying data on your screen
}
void loop() {
int aRead = analogRead(A0); //plug a potentiometer or a resistor to pin A0, so you can see data being transfer
float x = aRead/1024.0*5.0; //generate a float number, with this method you can use any time of data pretty much
dtostrf(x, 3, 2, t); //convers the float or integer to a string. (floatVar, minStringWidthIncDecimalPoint, numVarsAfterDecimal, empty array);
Serial.println(Val); // print the character
delay(500);
}
// function: what to do when asked for data
void requestEvent() {
Wire.write(t);
}
// what to do when receiving data from master
void receiveEvent(int howMany)
{Val = Wire.read();}
Como bytes
Passar os dados numéricos como bytes. Implica a reconstituição dos tipos com uma union no receptor.
Forma encontrada no seguinte link:
https://forum.arduino.cc/index.php?topic=45445.0
Master
// master reader
byte i2c_receive[32];
int i = 0;
// I2C limit write to 32 bytes
Wire.requestFrom(8, 32); // request 6 bytes from slave device #8
while (Wire.available()) { // slave may send less than requested
char c = Wire.read(); // receive a byte as character
i2c_receive[i] = c;
i++;
}
union u_tag {
byte b[4];
double d_val;
long l_val;
} u[11];
for(i=0; i < 8; i++) {
u[i].b[0] = i2c_receive[i*4 + 0];
u[i].b[1] = i2c_receive[i*4 + 1];
u[i].b[2] = i2c_receive[i*4 + 2];
u[i].b[3] = i2c_receive[i*4 + 3];
}
Serial.print(u[0].l_val); Serial.println("\t");
[...]
Serial.print(u[7].d_val); Serial.println("\t");
Slave
Aproveitando ao maximo o limite de 32 bytes enviamos 8 variaveis, double ou long, o que prefaz 8 vezes 4 bytes.
// I2C limit write to 32 bytes Wire.write((byte*)&bodyEncoderLeftTotalPulses, 4); Wire.write((byte*)&bodyEncoderRightTotalPulses, 4); Wire.write((byte*)&bodySpeedPidSetPoint, 4); Wire.write((byte*)&bodySpeedPidInput, 4); Wire.write((byte*)&bodySpeedPidOutput, 4); Wire.write((byte*)&bodySteeringPidInput, 4); Wire.write((byte*)&bodySteeringPidOutput, 4); Wire.write((byte*)&bodyMoveDistanceRemain, 4);
O slave pode enviar menos bytes que o requerido pelo master.