Estabelecer uma comunicação entre diversos dispositivos pode ser prático, sobretudo em projectos de domótica. Uma técnica empregada com frequência é o protocolo I2C (ou TWI). O protocolo I2C é um método que permite conectar diversas placas mestres e diversas placas escravas, de modo a comunicar até 128 dispositivos. Ele possibilita conexões assíncronas entre diversos componentes, para compartilhar informações por meio de um “barramento comum”. Já falamos anteriormente sobre a comunicação pela porta serial (dita UART), utilizada para enviar o código ao Arduino através de um computador ou para conectar dois dispositivos em particular via Bluetooth.
Obs.: Vale observar que a comunicação I2C é originalmente concebida para a comunicação entre placas. Assim, ela não é adaptada à comunicação à distância (>1m).
Equipamento
- Computador
- Arduino UNO (2 ou mais)
- Cabos jumper M/M (3 vezes a quantidade de placas)
Esquema de ligação do barramento I2C entre placas Arduino
O protocolo I2C também possibilita estabelecer comunicação entre diferentes sistemas (sensores, ecrã LCD, Raspberry Pi, etc.). Um exemplo interessante é a comunicação entre diversas placas Arduino. Para isso, é preciso escrever ao menos dois programas, um para a placa mestre e outro para as placas escravas.
A comunicação I2C é definida por um barramento de dois fios (também chamado de TWI, Two Wire Interface) e um endereço. Os pinos utilizados pela comunicação I2C normalmente são fixos para cada dispositivo. Há um pino para o envio dos dados (SDA Serial Data Line) e outro para o relógio de sincronização (SLC Serial Clock Line).
Pinos I2C/TWI:
- Uno, Ethernet A4 (SDA), A5 (SCL)
- Mega2560 20 (SDA), 21 (SCL)
- Leonardo 2 (SDA), 3 (SCL)
- Due 20 (SDA), 21 (SCL), SDA1, SCL1
No exemplo abaixo, utilizamos uma placa Arduino Uno, e portanto os pinos A4 e A5.
Para que as duas placas comuniquem-se entre si, é preciso ligá-las corretamente (A4 com A4 e A5 com A5) e não esquecer de conectar as terras (GND) conforme indicado no esquema a seguir.
Atenção: Se os pinos A4 e A5 forem conectados aos pinos de uma placa não alimentada, o código irá travar no momento da transmissão.
Em geral, uma das placas envia as informações (Writer) e uma outra as recebe (Reader).
Código para configuração do barramento I2C
A biblioteca Wire.h permite definir a comunicação serial no barramento I2C com facilidade. As funções são similares às da biblioteca Serial.
- Wire.begin() permite configurar o endereço do dispositivo. O argumento da função pode ser vazio para os dispositivos mestres.
- Wire.write() permite o envio de bytes.
- Wire.requestFrom() gerencia a função de recepção de solicitações
- Wire.beginTransmission() inicia a transmissão de dados e define o receptor.
- Wire.endTransmission termina a transmissão de dados
- Wire.onRequest() gerencia a função de recepção de solicitações
- Wire.onRecieve() gerencia a função de recepção de dados
Código da placa Mestre
#include <Wire.h>
# define I2C_SLAVE1_ADDRESS 11
# define I2C_SLAVE2_ADDRESS 12
#define PAYLOAD_SIZE 2
int n = 0;
void setup()
{
Wire.begin();
Serial.begin(9600);
Serial.println(F("-------------------------------------I am the Master"));
delay(1000);
//Request value of n to slave
Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1);
n = Wire.read();
Serial.print(F("recieved value : "));
Serial.println(n);
//Send value 12 to slave
Wire.beginTransmission(I2C_SLAVE1_ADDRESS);
Wire.write(12);
Serial.print(F("sending value : "));
Serial.println(12);
Wire.endTransmission();
Serial.print(" ");
//Request value of n to slave after change
Wire.requestFrom(I2C_SLAVE1_ADDRESS, 1);
n = Wire.read();
Serial.print(F(" new recieved value : "));
Serial.println(n);
}
void loop()
{
delay(100);
}
Código da placa Escrava
#include <Wire.h>
# define I2C_SLAVE_ADDRESS 11 // 12 pour l'esclave 2 et ainsi de suite
#define PAYLOAD_SIZE 2
void setup()
{
Wire.begin(I2C_SLAVE_ADDRESS);
Serial.begin(9600);
Serial.println("-------------------------------------I am Slave1");
delay(1000);
Wire.onRequest(requestEvents);
Wire.onReceive(receiveEvents);
}
void loop() {}
int n = 0;
void requestEvents()
{
Serial.println(F("---> recieved request"));
Serial.print(F("sending value : "));
Serial.println(n);
Wire.write(n);
}
void receiveEvents(int numBytes)
{
Serial.println(F("---> recieved events"));
n = Wire.read();
Serial.print(numBytes);
Serial.println(F("bytes recieved"));
Serial.print(F("recieved value : "));
Serial.println(n);
}
Abra o monitor serial das placas escravas antes do monitor da placa mestre.
No monitor serial da placa mestre:
No monitor serial da placa Escrava 1:
Podemos observar que as duas placas trocam informações. É muito simples estender este exemplo para diversas placas Arduino (Leonardo, Mini, etc.), adaptando-se as ligações e o endereço do componente no código escravo.
.
Código para identificar os periféricos conectados ao barramento I2C
Um bom teste para saber se os seus dispositivos comunicam-se bem entre si é utilizar o código abaixo (I2CScanner), que retorna os endereços de todos os dispositivos conectados à placa mestre.
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(9600);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println(F("\nI2C Scanner"));
}
void loop()
{
byte error, address;
int nDevices;
Serial.println(F("Scanning..."));
nDevices = 0;
for (address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.print(address, HEX);
Serial.println(" !");
nDevices++;
}
else if (error == 4)
{
Serial.print("Unknown error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0)
Serial.println(F("No I2C devices found\n"));
else
Serial.println(F("done\n"));
delay(5000); // wait 5 seconds for next scan
}
Se tiver qualquer dificuldade para estabelecer uma comunicação I2C entre diferentes dispositivos, deixe um comentário abaixo ou contacte-nos.
Fontes
- Referência na biblioteca Wire do Arduino
- Nota sobre o conceito I2C Master Writer e Master Reader

