Neste post, será demonstrado o uso do protocolo I2C para comunicação em vários modos: Mestre e Escravo; Escravo e Mestre com confirmação de Envio e Mestre e dois Escravos, entre Arduinos. Ao fim, será desenvolvido um projeto de comunicação entre Arduinos e módulos I2C em que um Arduino UNO (mestre) irá receber os dados do BMP280 (escravo) e os dados do DHT11 enviados do Arduino NANO (escravo). Após o Arduino UNO (mestre) receber os dados, ele irá exibir os dados no display LCD (escravo).

Protocolo I2C
Para este post, serão utilizados os seguintes materiais:
Para o projeto de exemplificação, será utilizado, adicionalmente o seguinte material:

O I2C (sigla de Inter-Integrated Circuit), Circuito Interintegrado, é um protocolo que foi desenvolvido pela empresa Philips Semiconductors em 1982. Este protocolo é utilizado para conectar periféricos de baixa velocidade a microcontroladores para comunicação de curta distância. O protocolo I2C envolve o uso de duas linhas para enviar e receber dados: um pino de relógio serial (SCL), que a placa controladora do Arduino pulsa em intervalos regulares e um pino de dados serial (SDA), pelo qual os dados são enviados entre os dois dispositivos. Em geral, você só pode ter um controlador e até 127 dispositivos periféricos. (Existem exceções, como dispositivos de endereço multi-principal e de 10 bits, mas são raros). Como o protocolo I2C permite que cada dispositivo habilitado tenha seu próprio endereço exclusivo, e como o controlador e os dispositivos periféricos se revezam na comunicação em uma única linha, é possível que a placa Arduino se comunique com muitos dispositivos, ou outras placas, usando apenas dois pinos do seu microcontrolador. Mas, isso também significa que se você tiver dois periféricos e ambos tiverem o endereço, por exemplo, 0x22, você não poderá ter os dois nas mesmas linhas I2C. Existem algumas soluções alternativas:

Jumpers de seleção de endereço I2C do Módulo Serial I2C para Display LCD com chip PCF8574T
Para utilizar a comunicação Mestre e Escravo, monte o hardware de acordo com o seguinte esquemático:
Em seguida, carregue os seguintes algoritmos nas respectivas placas Arduino Uno e Mega:
/******************************************************************************
Comunicação Mestre e Escravo - Sketch para MASTER
Sketch de Exemplo
Criado em 12 de Agosto de 2022
por Michel Galvão
Placa: Arduino Uno
O sketch usa 4170 bytes (12%) de espaço de armazenamento para programas.
O máximo são 32256 bytes.
Variáveis globais usam 257 bytes (12%) de memória dinâmica, deixando 1791 bytes
para variáveis locais. O máximo são 2048 bytes.
Blog Eletrogate - Veja este e outros projetos e tutoriais no blog Eletrogate
https://blog.eletrogate.com/
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Inclusão da biblioteca
#include <Wire.h> // Biblioteca nativa do core Arduino
// Variáveis globais
const int slaveAddress = 0x08; // constante armazena o endereço do dispositivo slave
int x = 0; // variável de armazenagem do valor para envio
void setup() {
Wire.begin(); // inicia a comunicação I2C
}
void loop() {
Wire.beginTransmission(slaveAddress); // transmite para o dispositivo slave
// Cria e formata a mensagem para envio
String message = "O valor de x é ";
message.concat(x);
message.concat("\n");
Wire.write(message.c_str());// envia a mensagem
Wire.endTransmission(); //para de transmitir
x++; // incremento da variável
delay(500); // pausa de 500 milissegundos
}/******************************************************************************
Comunicação Mestre e Escravo - Sketch para SLAVE
Sketch de Exemplo
Criado em 12 de Agosto de 2022
por Michel Galvão
Placa: Arduino Mega
O sketch usa 5076 bytes (1%) de espaço de armazenamento para programas.
O máximo são 253952 bytes.
Variáveis globais usam 406 bytes (4%) de memória dinâmica, deixando 7786 bytes
para variáveis locais. O máximo são 8192 bytes.
Blog Eletrogate - Veja este e outros projetos e tutoriais no blog Eletrogate
https://blog.eletrogate.com/
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Inclusão da biblioteca
#include <Wire.h> // Biblioteca nativa do core Arduino
// Variáveis globais
const int myAddress = 0x08; // armazena o endereço deste dispositivo (slave)
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia o dispositivo com o endereço definido anteriormente
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino MEGA");
}
void loop() {}
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
}
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}
A cada 500 milissegundos, o dispositivo MASTER (Arduino Uno) envia uma mensagem, contendo o valor da variável x, para o dispositivo SLAVE. O valor da variável x é incrementado (adicionado 1) a cada execução do loop.
Ao ser acionado o evento de recebimento, o dispositivo SLAVE (Arduino MEGA) recebe a mensagem enviada pelo dispositivo MASTER e o imprime na Serial.
Começando o sketch, incluímos a biblioteca necessária para a comunicação I2C:
// Inclusão da biblioteca #include <Wire.h> // Biblioteca nativa do core Arduino
Em seguida, declaramos as variáveis globais que armazenaram o endereço do dispositivo SLAVE e a variável de armazenagem do valor para envio no dispositivo SLAVE:
// Variáveis globais const int slaveAddress = 0x08; // constante armazena o endereço do dispositivo slave int x = 0; // variável de armazenagem do valor para envio
Em void setup(), inicializamos a comunicação I2C através da função Wire.begin();:
void setup() {
Wire.begin(); // inicia a comunicação I2C
}Já no void loop(), é iniciada a transmissão no endereço armazenado na variável slaveAddress (0x08):
Wire.beginTransmission(slaveAddress); // transmite para o dispositivo slave
Em seguida, armazenamos a mensagem de envio na variável message:
// Cria e formata a mensagem para envio
String message = "O valor de x é ";
message.concat(x);
message.concat("\n");Após a criação da mensagem de envio, a enviamos para o dispositivo SLAVE atráves da função Wire.write():
Wire.write(message.c_str());// envia a mensagem Wire.endTransmission(); //para de transmitir
Logo após, incrementamos o valor da variável x e fazemos uma pausa de 500 milissegundos:
x++; // incremento da variável delay(500); // pausa de 500 milissos
Começando o sketch, incluímos a biblioteca necessária para a comunicação I2C:
// Inclusão da biblioteca #include <Wire.h> // Biblioteca nativa do core Arduino
Em seguida, declaramos a variável global que armazenará o seu endereço (SLAVE):
// Variáveis globais const int myAddress = 0x08; // armazena o endereço deste dispositivo (slave)
Em void setup(), inicializamos a Serial e a comunicação I2C. Também registramos o evento de callback que fará o recebimento de mensagem que será acionado quando o dispositivo SLAVE receber alguma mensagem:
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia o dispositivo com o endereço definido anteriormente
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino MEGA");
}Em void loop(), não realizamos nenhuma ação, pois todas ações serão tratadas na função de callback:
void loop() {}Na função de callback receiveEvent(), fazemos a leitura da mensagem recebida na comunicação I2C através da função readString() e imprimimos a mensagem na Serial:
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
}Na função readString(), fazemos a leitura da mensagem recebida na comunicação I2C. Enquanto houver bytes disponíveis para leitura, armazenamo-los na variável retorno. Após todos os bytes terem sidos lidos, toda a mensagem armazenada é retornada para o chamado da função:
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}Para utilizar a comunicação Mestre e dois Escravos, monte o hardware de acordo com o seguinte esquemático:
Em seguida, carregue os seguintes algoritmos nas respectivas placas Arduino Uno, Mega e Nano:
/******************************************************************************
Comunicação Mestre e dois Escravo - Sketch para MASTER
Sketch de Exemplo
Criado em 15 de Agosto de 2022
por Michel Galvão
Placa: Arduino Uno
O sketch usa 5042 bytes (15%) de espaço de armazenamento para programas.
O máximo são 32256 bytes.
Variáveis globais usam 279 bytes (13%) de memória dinâmica, deixando 1791 bytes
para variáveis locais. O máximo são 2048 bytes.
Blog Eletrogate - Veja este e outros projetos e tutoriais no blog Eletrogate
https://blog.eletrogate.com/
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Inclusão da biblioteca
#include <Wire.h> // Biblioteca nativa do core Arduino
// Variáveis globais
const int slaveAddressMega = 0x08; // constante armazena o endereço do dispositivo slave Mega
const int slaveAddressNano = 0x09; // constante armazena o endereço do dispositivo slave Nano
int m = 0; // variável de armazenagem do valor para envio para o slave Mega
int n = 0; // variável de armazenagem do valor para envio para o slave Nano
void setup() {
Wire.begin(); // inicia a comunicação I2C
}
void loop() {
Wire.beginTransmission(slaveAddressMega); // transmite para o dispositivo slave
// Cria e formata a mensagem para envio
String messageM = "O valor de m é ";
messageM.concat(m);
messageM.concat("\n");
Wire.write(messageM.c_str());// envia a mensagem
Wire.endTransmission(); //para de transmitir
Wire.beginTransmission(slaveAddressNano); // transmite para o dispositivo slave
// Cria e formata a mensagem para envio
String messageN = "O valor de n é ";
messageN.concat(n);
messageN.concat("\n");
Wire.write(messageN.c_str());// envia a mensagem
Wire.endTransmission(); //para de transmitir
// atribue um valor entre 0 e 100 para a variável m, através
// da função random();
// Documentação: https://www.arduino.cc/reference/en/language/functions/random-numbers/random/
m = random(0,101);
// Incrementa o valor da variável n
n++;
delay(500); // pausa de 500 milissegundos
}/******************************************************************************
Comunicação Mestre e dois Escravo - Sketch para SLAVE
Sketch de Exemplo
Criado em 15 de Agosto de 2022
por Michel Galvão
Placa: Arduino Nano
O sketch usa 4362 bytes (14%) de espaço de armazenamento para programas.
O máximo são 32256 bytes.
Variáveis globais usam 406 bytes (19%) de memória dinâmica, deixando 1791 bytes
para variáveis locais. O máximo são 2048 bytes.
Blog Eletrogate - Veja este e outros projetos e tutoriais no blog Eletrogate
https://blog.eletrogate.com/
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Inclusão da biblioteca
#include <Wire.h> // Biblioteca nativa do core Arduino
// Variáveis globais
const int myAddress = 0x09; // constante armazena o endereço do dispositivo slave
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia o dispositivo com o endereço definido anteriormente
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino NANO");
}
void loop() {}
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
}
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}/******************************************************************************
Comunicação Mestre e dois Escravo - Sketch para SLAVE
Sketch de Exemplo
Criado em 15 de Agosto de 2022
por Michel Galvão
Placa: Arduino Mega
O sketch usa 5076 bytes (1%) de espaço de armazenamento para programas.
O máximo são 253952 bytes.
Variáveis globais usam 406 bytes (4%) de memória dinâmica, deixando 7786 bytes
para variáveis locais. O máximo são 8192 bytes.
Blog Eletrogate - Veja este e outros projetos e tutoriais no blog Eletrogate
https://blog.eletrogate.com/
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Inclusão da biblioteca
#include <Wire.h> // Biblioteca nativa do core Arduino
// Variáveis globais
const int myAddress = 0x08; // armazena o endereço deste dispositivo (slave)
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia o dispositivo com o endereço definido anteriormente
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino MEGA");
}
void loop() {}
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
}
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}A cada 500 milissegundos, o dispositivo MASTER (Arduino Uno) envia uma mensagem, contendo o valor da variável m (valor aleatório entre 0 e 100), para o dispositivo SLAVE Mega. O valor da variável n é incrementado (adicionado 1) a cada execução do loop;
Ao ser acionado o evento de recebimento, o dispositivo SLAVE (Arduino Nano) recebe a mensagem enviada pelo dispositivo MASTER e o imprime na Serial.
Ao ser acionado o evento de recebimento, o dispositivo SLAVE (Arduino MEGA) recebe a mensagem enviada pelo dispositivo MASTER e o imprime na Serial.
Começando o sketch, incluímos a biblioteca necessária para a comunicação I2C:
// Inclusão da biblioteca #include <Wire.h> // Biblioteca nativa do core Arduino
Em seguida, declaramos as variáveis globais que armazenaram os endereços dos dispositivos SLAVE Mega e Nano e também as variáveis de armazenagem dos valores para envio nos dispositivos SLAVE:
// Variáveis globais const int slaveAddressMega = 0x08; // constante armazena o endereço do dispositivo slave Mega const int slaveAddressNano = 0x09; // constante armazena o endereço do dispositivo slave Nano int m = 0; // variável de armazenagem do valor para envio para o slave Mega int n = 0; // variável de armazenagem do valor para envio para o slave Nano
Em void setup(), inicializamos a comunicação I2C através da função Wire.begin();:
void setup() {
Wire.begin(); // inicia a comunicação I2C
}Já no void loop(), é iniciada a transmissão no endereço armazenado na variável slaveAddressMega (0x08):
Wire.beginTransmission(slaveAddressMega); // transmite para o dispositivo slave
Em seguida, armazenamos a mensagem de envio na variável messageM:
// Cria e formata a mensagem para envio
String messageM = "O valor de m é ";
messageM.concat(m);
messageM.concat("\n");Após a criação da mensagem de envio, a enviamos para o dispositivo SLAVE atráves da função Wire.write():
Wire.write(messageM.c_str());// envia a mensagem Wire.endTransmission(); //para de transmitir
A seguir, é iniciada a transmissão no endereço armazenado na variável slaveAddressNano (0x09):
Wire.beginTransmission(slaveAddressNano); // transmite para o dispositivo slave
Em seguida, armazenamos a mensagem de envio na variável messageN:
// Cria e formata a mensagem para envio
String messageN = "O valor de n é ";
messageN.concat(m);
messageN.concat("\n");Após a criação da mensagem de envio, a enviamos para o dispositivo SLAVE atráves da função Wire.write():
Wire.write(messageN.c_str());// envia a mensagem Wire.endTransmission(); //para de transmitir
Logo após, fazemos a atualização dos valores das variáveis m e n: atribuímos um valor aleatório entre 0 e 100 (através da função random)para a variável m e incrementamos o valor da variável n :
// atribue um valor entre 0 e 100 para a variável m, através // da função random(); // Documentação: https://www.arduino.cc/reference/en/language/functions/random-numbers/random/ m = random(0,101); // Incrementa o valor da variável n n++;
Por fim, fazemos uma pausa de 500 milissegundos:
delay(500); // pausa de 500 milissegundos }
Começando o sketch, incluímos a biblioteca necessária para a comunicação I2C:
// Inclusão da biblioteca #include <Wire.h> // Biblioteca nativa do core Arduino
Em seguida, declaramos a variável global que armazenará o seu endereço (SLAVE):
// Variáveis globais const int myAddress = 0x09; // armazena o endereço deste dispositivo (slave)
Em void setup(), inicializamos a Serial e a comunicação I2C. Também registramos o evento de callback que fará o recebimento de mensagem que será acionado quando o dispositivo SLAVE receber alguma mensagem:
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia o dispositivo com o endereço definido anteriormente
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino NANO");
}Em void loop(), não realizamos nenhuma ação, pois todas ações serão tratadas na função de callback:
void loop() {}Na função de callback receiveEvent(), fazemos a leitura da mensagem recebida na comunicação I2C através da função readString() e imprimimos a mensagem na Serial:
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
}Na função readString(), fazemos a leitura da mensagem recebida na comunicação I2C. Enquanto houver bytes disponíveis para leitura, armazenamo-los na variável retorno. Após todos os bytes terem sidos lidos, toda a mensagem armazenada é retornada para o chamado da função:
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}Começando o sketch, incluímos a biblioteca necessária para a comunicação I2C:
// Inclusão da biblioteca #include <Wire.h> // Biblioteca nativa do core Arduino
Em seguida, declaramos a variável global que armazenará o seu endereço (SLAVE):
// Variáveis globais const int myAddress = 0x08; // armazena o endereço deste dispositivo (slave)
Em void setup(), inicializamos a Serial e a comunicação I2C. Também registramos o evento de callback que fará o recebimento de mensagem que será acionado quando o dispositivo SLAVE receber alguma mensagem:
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia o dispositivo com o endereço definido anteriormente
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino MEGA");
}Em void loop(), não realizamos nenhuma ação, pois todas ações serão tratadas na função de callback:
void loop() {}Na função de callback receiveEvent(), fazemos a leitura da mensagem recebida na comunicação I2C através da função readString() e imprimimos a mensagem na Serial:
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
}Na função readString(), fazemos a leitura da mensagem recebida na comunicação I2C. Enquanto houver bytes disponíveis para leitura, armazenamo-los na variável retorno. Após todos os bytes terem sidos lidos, toda a mensagem armazenada é retornada para o chamado da função:
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}Para utilizar a Comunicação Escravo e Mestre com Confirmação de Envio, monte o hardware de acordo com o seguinte esquemático:
Em seguida, carregue os seguintes algoritmos nas respectivas placas Arduino Mega e Nano:
/******************************************************************************
Comunicação Mestre e Escravo - Sketch para MASTER
Sketch de Exemplo
Criado em 15 de Agosto de 2022
por Michel Galvão
Placa: Arduino Mega
O sketch usa 6190 bytes (2%) de espaço de armazenamento para programas.
O máximo são 253952 bytes.
Variáveis globais usam 460 bytes (5%) de memória dinâmica, deixando 7786 bytes
para variáveis locais. O máximo são 8192 bytes.
Blog Eletrogate - Veja este e outros projetos e tutoriais no blog Eletrogate
https://blog.eletrogate.com/
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Inclusão da biblioteca
#include <Wire.h> // Biblioteca nativa do core Arduino
// Variáveis globais
const int myAddress = 0x07; // armazena o endereço deste dispositivo (master)
const int slaveAddress = 0x08; // constante armazena o endereço do dispositivo slave
int x = 0; // variável de armazenagem do valor para envio
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia a comunicação I2C
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino MEGA");
}
void loop() {
Wire.beginTransmission(slaveAddress); // transmite para o dispositivo slave
// Cria e formata a mensagem para envio
String message = "O valor de x é ";
message.concat(x);
message.concat("\n");
Wire.write(message.c_str());// envia a mensagem
Wire.endTransmission(); //para de transmitir
x++; // incremento da variável
delay(500); // pausa de 500 milissegundos
}
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
}
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}/******************************************************************************
Comunicação Mestre e Escravo - Sketch para SLAVE
Sketch de Exemplo
Criado em 12 de Agosto de 2022
por Michel Galvão
Placa: Arduino Nano
O sketch usa 5266 bytes (17%) de espaço de armazenamento para programas.
O máximo são 30720 bytes.
Variáveis globais usam 465 bytes (22%) de memória dinâmica, deixando 1583 bytes
para variáveis locais. O máximo são 2048 bytes.
Blog Eletrogate - Veja este e outros projetos e tutoriais no blog Eletrogate
https://blog.eletrogate.com/
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Inclusão da biblioteca
#include <Wire.h> // Biblioteca nativa do core Arduino
// Variáveis globais
const int myAddress = 0x08; // armazena o endereço deste dispositivo (slave)
const int masterAddress = 0x07; // armazena o endereço do dispositivo master
bool recebido = false; // variável de controle do envio da confirmação de recebimento
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia o dispositivo com o endereço definido anteriormente
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino NANO");
}
void loop() {
if (recebido) { // se true, será enviado a mensagem de confirmação
Wire.beginTransmission(masterAddress); // transmite para o dispositivo master
// Cria e formata a mensagem para envio
String message;
message.concat("A mensagem foi recebida");
message.concat("\n");
Wire.write(message.c_str());// envia a mensagem
Wire.endTransmission(); //para de transmitir
recebido = false;
}
}
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
recebido = true;
}
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}A cada 500 milissegundos, o dispositivo MASTER (Arduino Mega) envia uma mensagem, contendo o valor da variável x, para o dispositivo SLAVE Mega. O valor da variável x é incrementado (adicionado 1) a cada execução do loop. Ao ser enviado, o dispositivo SLAVE enviará uma mensagem de confirmação se algo foi recebido.
Ao ser acionado o evento de recebimento, o dispositivo SLAVE (Arduino Nano) recebe a mensagem enviada pelo dispositivo MASTER e envia uma mensagem de confirmação para dispositivo MASTER. A mensagem recebida é impressa na Serial.
Começando o sketch, incluímos a biblioteca necessária para a comunicação I2C:
// Inclusão da biblioteca #include <Wire.h> // Biblioteca nativa do core Arduino
Em seguida, declaramos as variáveis globais que armazenaram o seu endereço (MASTER), o endereço do dispositivo SLAVE (Nano) e também a variável de armazenagem do valor para envio no dispositivo SLAVE:
// Variáveis globais const int myAddress = 0x07; // armazena o endereço deste dispositivo (master) const int slaveAddress = 0x08; // constante armazena o endereço do dispositivo slave int x = 0; // variável de armazenagem do valor para envio
Em void setup(), inicializamos a Serial e a comunicação I2C. Também registramos o evento de callback que fará o recebimento de mensagem que será acionado quando o dispositivo receber a mensagem de confirmação de recebimento:
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia a comunicação I2C
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino MEGA");
}Já no void loop(), é iniciada a transmissão no endereço armazenado na variável slaveAddress (0x08):
Wire.beginTransmission(slaveAddress); // transmite para o dispositivo slave
Em seguida, armazenamos a mensagem de envio na variável message:
// Cria e formata a mensagem para envio
String message = "O valor de x é ";
message.concat(x);
message.concat("\n");Após a criação da mensagem de envio, a enviamos para o dispositivo SLAVE atráves da função Wire.write():
Wire.write(message.c_str());// envia a mensagem Wire.endTransmission(); //para de transmitir
Logo após, fazemos ao incremento do valor da variável x e também fazemos uma pausa de 500 milissegundos:
x++; // incremento da variável delay(500); // pausa de 500 milissegundos
Começando o sketch, incluímos a biblioteca necessária para a comunicação I2C:
// Inclusão da biblioteca #include <Wire.h> // Biblioteca nativa do core Arduino
Em seguida, declaramos as variáveis globais que armazenaram o seu endereço (SLAVE), o endereço do dispositivo MASTER (Mega) e também a variável de controle do envio da confirmação de recebimento:
// Variáveis globais const int myAddress = 0x08; // armazena o endereço deste dispositivo (slave) const int masterAddress = 0x07; // armazena o endereço do dispositivo master bool recebido = false; // variável de controle do envio da confirmação de recebimento
Em void setup(), inicializamos a Serial e a comunicação I2C. Também registramos o evento de callback que fará o recebimento de mensagem enviada do dispositivo MASTER:
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
Wire.begin(myAddress); // inicia o dispositivo com o endereço definido anteriormente
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino NANO");
}Em void loop(), caso a variável recebido possua o valor true, é iniciada a transmissão de confirmação de recebimento de mensagem para o dispositivo no endereço armazenado na variável masterAddress (0x07):
void loop() {
if (recebido) { // se true, será enviado a mensagem de confirmação
Wire.beginTransmission(masterAddress); // transmite para o dispositivo master
// Cria e formata a mensagem para envio
String message;
message.concat("A mensagem foi recebida");
message.concat("\n");
Wire.write(message.c_str());// envia a mensagem
Wire.endTransmission(); //para de transmitir
recebido = false;
}
}Na função de callback receiveEvent(), fazemos a leitura da mensagem recebida na comunicação I2C através da função readString() e imprimimos a mensagem na Serial. Também atribuímos o valor true para a variável recebido:
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
recebido = true;
}Na função readString(), fazemos a leitura da mensagem recebida na comunicação I2C. Enquanto houver bytes disponíveis para leitura, armazenamo-los na variável retorno. Após todos os bytes terem sidos lidos, toda a mensagem armazenada é retornada para o chamado da função:
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}Para realizar o projeto, monte o hardware de acordo com o seguinte esquemático:

Antes de fazer o upload dos sketch’s para as placas Arduino, é necessário identificar os endereços I2C dos módulos conectados nos arduinos. Para isso, abra o sketch, através da arduino IDE, localizado na aba Arquivo → Exemplos → Wire → i2c_scanner:

Após abri-lo, faça o upload do sketch na placa arduino uno. Em seguida, desconecte os fios de alimentação VCC e GND do módulo BMP280 para encontrar o endereço I2C do display LCD I2C no monitor serial aberto:

O endereço encontrado foi o 0x27.
Após encontrar o endereço do display LCD I2C, reconecte os fios de alimentação VCC e GND do módulo BMP280 e veja no monitor serial o endereço do módulo BMP280:

O endereço encontrado foi o 0x76.
/******************************************************************************
Comunicação Mestre e Escravo - Sketch para MASTER
Sketch de Exemplo
Criado em 15 de Agosto de 2022
por Michel Galvão
Placa: Arduino Uno
O sketch usa 9180 bytes (28%) de espaço de armazenamento para programas.
O máximo são 32256 bytes.
Variáveis globais usam 530 bytes (25%) de memória dinâmica. O máximo são 1508 bytes.
Blog Eletrogate - Veja este e outros projetos e tutoriais no blog Eletrogate
https://blog.eletrogate.com/
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Inclusão da biblioteca
#include <Wire.h> // Biblioteca nativa do core Arduino
#include <LiquidCrystal_I2C.h> // Necessária a instalação da bibliteca
// Variáveis globais
const int myAddress = 0x07; // constante armazena o endereço deste dispositivo (master)
const int slaveAddress = 0x08; // constante armazena o endereço do dispositivo slave
float temperatura, pressao, umidade; // variávies do tempo
// Instanciação dos objetos das Classes
LiquidCrystal_I2C lcd(0x27, 16, 2); // Instanciação do objeto da classe do display LCD
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
lcd.init(); // Inicializa o display LCD I2C
lcd.backlight(); // Liga a luz de fundo do dispaly LCD I2C
Wire.begin(myAddress); // Inicia a comunicação I2C
Wire.onReceive(receiveEvent); //Registra o evento de recebimento de mensagem
Serial.println("Software do arduino UNO");
}
void loop() {
Wire.beginTransmission(slaveAddress); // transmite para o dispositivo slave
Wire.write("getDados");// envia a mensagem
Wire.endTransmission(); //para de transmitir
delay(500); // pausa de 500 milissegundos
// Imprimimos no dispaly LCD I2C o valro das variáveis de pressão, umidadade e temperatura
lcd.setCursor(0, 0);
lcd.print("P:");
lcd.print(pressao / 100); // Converte a presão de Pascal para Hectopascal e a imprime
lcd.print(" hPa ");
lcd.setCursor(0, 1);
lcd.print("U:");
lcd.print(umidade);
lcd.print("% T:");
lcd.print(temperatura);
lcd.write(223); // imprime o caractere º (11011111 convertido para decimal 223)
// explicação de como obter: https://blog.eletrogate.com/monitoramento-de-ponto-de-orvalho-com-arduino/#titulo7
lcd.print("C ");
}
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
int index1, index2; // cria as variáveis locais para armazenar os índices de
// extração de substring da String message.
index1 = 0;
index2 = message.indexOf('&', index1);
temperatura = message.substring(index1, index2).toFloat(); // extrai a string e a converte para float
index1 = index2 + 1;
index2 = message.indexOf('&', index1);
pressao = message.substring(index1, index2).toFloat(); // extrai a string e a converte para float
index1 = index2 + 1;
index2 = message.indexOf('&', index1);
umidade = message.substring(index1, index2).toFloat(); // extrai a string e a converte para float
}
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}/******************************************************************************
Comunicação Mestre e Escravo - Sketch para SLAVE
Sketch de Exemplo
Criado em 12 de Agosto de 2022
por Michel Galvão
Placa: Arduino Nano
O sketch usa 14864 bytes (48%) de espaço de armazenamento para programas.
O máximo são 30720 bytes.
Variáveis globais usam 559 bytes (27%) de memória dinâmica. O máximo são 1489 bytes.
Blog Eletrogate - Veja este e outros projetos e tutoriais no blog Eletrogate
https://blog.eletrogate.com/
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Inclusão da biblioteca
#include <Wire.h> // Biblioteca nativa do core Arduino
#include <Adafruit_BMP280.h> // Necessária a instalação da bibliteca
#include <DHT.h> // Necessária a instalação da bibliteca
// Variáveis globais
const int myAddress = 0x08; // constante armazena o endereço deste dispositivo (slave)
const int masterAddress = 0x07; // constante armazena o endereço do dispositivo master
const int bmp280Address = 0x76; // constante armazena o endereço do dispositivo master
const int DHTPIN = 2; // constante armazena o pino ao qual o DHT11 está conectado
const uint8_t DHTTYPE = DHT11; // constante armazena o tipo do DHT (DHT11)
float temperatura, pressao, umidade; // variávies do tempo
bool recebido = false; // variável de controle do envio da confirmação de recebimento
// Instanciação dos objetos das Classes
Adafruit_BMP280 bmp; // Instanciação do objeto da classe do BMP280
DHT dht(DHTPIN, DHTTYPE); // Instanciação do objeto da classe do DHT11
void setup() {
Serial.begin(115200); // Configura a taxa de transferência em bits por
// segundo (baud rate) para transmissão serial.
Serial.println();
bmp.begin(bmp280Address); // Inicializa o BMP280 no endereço I2C
dht.begin(); // Inicializa o DHT11
Wire.begin(myAddress); // inicia o dispositivo com o endereço definido anteriormente
Wire.onReceive(receiveEvent); //registra o evento de recebimento de mensagem
Serial.println("Software do arduino NANO");
// Atribui os valores iniciais das variáveis do tempo
temperatura = bmp.readTemperature();
pressao = bmp.readPressure();
umidade = dht.readHumidity();
}
void loop() {
if (recebido) { // se true, será enviado a mensagem de confirmação
// Atribui os valores das variáveis do tempo
temperatura = bmp.readTemperature();
pressao = bmp.readPressure();
umidade = dht.readHumidity();
Wire.beginTransmission(masterAddress); // transmite para o dispositivo master
// Cria e formata a mensagem para envio
String message;
message.concat(temperatura);
message.concat("&");
message.concat(pressao);
message.concat("&");
message.concat(umidade);
message.concat(";\n");
Wire.write(message.c_str());// envia a mensagem
Wire.endTransmission(); //para de transmitir
recebido = false; // atribui o valor false para a variável de controle do
// envio da confirmação de recebimento.
}
}
void receiveEvent(int howMany) {
String message = readString();
Serial.print(message); // imprime a mensagem recebida
recebido = true; // atribui o valor true para a variável de controle do
// envio da confirmação de recebimento.
}
String readString() {
String retorno;
while (Wire.available()) { // Enquanto houver bytes disponíveis para leitura, ...
char c = Wire.read(); // recebe o byte como caractere
retorno += c;
}
return retorno;
}A cada 500 milissegundos, o dispositivo MASTER (Arduino Uno) envia uma mensagem com qualquer valor, para o dispositivo SLAVE. Também a cada 500 milissegundos, é exibido no display LCD a pressão atmosférica, a umidade atmosférica e a temperatura ambiente. Ao ser recebido de volta a mensagem contendo os dados atmosféricos, é extraída da os valores das variáveis e as convertemos para valor decimal.
Ao ser recebido alguma mensagem, é permitido o envio dos dados atmosféricos. Caso haja permissão para envio dos dados atmosféricos, é lido os valores de pressão, temperatura e umidade e são enviados para o dispositivo MASTER.
Veja o vídeo abaixo para ver o funcionamento final:
Com isto, concluímos o post. Curtiu o post? Avalie e deixe um comentário! Siga-nos também no Instagram e nos marque quando fizer algum projeto nosso: @eletrogate. Até a próxima!
Conheça a Metodologia Eletrogate e ofereça aulas de robótica em sua escola!
|
A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.
Tenha a Metodologia Eletrogate dentro da sua Escola! Conheça nosso Programa de Robótica nas Escolas!