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.