blog-eletrogate-logo-desktop blog-eletrogate-logo-mobile
  • Categorias
    • Voltar
    • INICIANTES
    • INTERMEDIÁRIOS
    • AVANÇADOS
    • divide
    • Automação Residencial
    • Componentes Eletrônicos
    • Impressão 3D
    • IoT
    • Modelagem 3D
    • Módulos Wifi
    • Por trás da tecnologia
    • Projetos
    • Raspberry Pi
    • Robótica
    • Sensores
    • Shields
    • Sistemas Operacionais
    • Tipos de Arduino
    • Tutoriais
  • Apostilas
  • Quem Somos
  • Seja um redator
  • Trabalhe Conosco
    • Categorias
      • Voltar
      • INICIANTES
      • INTERMEDIÁRIOS
      • AVANÇADOS
      • divide
      • Automação Residencial
      • Componentes Eletrônicos
      • Impressão 3D
      • IoT
      • Modelagem 3D
      • Módulos Wifi
      • Por trás da tecnologia
      • Projetos
      • Raspberry Pi
      • Robótica
      • Sensores
      • Shields
      • Sistemas Operacionais
      • Tipos de Arduino
      • Tutoriais
    • Apostilas
    • Quem Somos
    • Seja um redator
    • Trabalhe Conosco
Loja Eletrogate
voltar
  • Introdução
  • Materiais Necessários para os Projetos de Comunicação I2C entre Arduinos
  • Comunicação I2C
  • Modo de Comunicação Mestre e Escravo
  • Modo de Comunicação Mestre e dois Escravos
  • Modo de Comunicação Escravo e Mestre com Confirmação de Envio
  • Hardware do Projeto
  • Software do Projeto
  • Demonstração de Funcionamento do Projeto
  • Conclusão
  • Sobre o Autor
Projetos

Comunicação I2C entre Arduinos

Eletrogate 19 de agosto de 2022Atualizado em: 31 mar 2023

Introdução

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


Materiais Necessários para os Projetos de Comunicação I2C entre Arduinos

Para este post, serão utilizados os seguintes materiais:

  • Mega 2560 R3 + Cabo Usb para Arduino
  • Uno R3 + Cabo Usb para Arduino
  • Nano V3.0 + Cabo Usb para Arduino
  • Jumpers – Macho/Macho – 20 Unidades de 20cm
  • Mini Protoboard 170 pontos

Para o projeto de exemplificação, será utilizado, adicionalmente o seguinte material:

  • Sensor de Pressão e Temperatura BMP280
  • Módulo Sensor De Umidade e Temperatura DHT11 – sem Led
  • Display LCD 16×2 com I2C e Backlight Azul

cta_cart


Comunicação I2C

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:

  • você pode desligar ou ligar um periférico de cada vez com um transistor;
  • algumas placas têm uma linha de seleção de endereço ou jumper  para que você possa definir um endereço diferente.

    Jumpers de seleção de endereço I2C do Módulo Serial I2C para Display LCD com chip PCF8574T

  • Alguns dispositivos têm um endereço reprogramável por software, onde aparecem como um endereço na inicialização, como por exemplo os microcontroladores AVR Atmega.

Modo de Comunicação Mestre e Escravo

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:

Algoritmo para placa Arduino Uno (MASTER)

/******************************************************************************
                    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
}

Algoritmo para Placa Arduino Mega (SLAVE)

/******************************************************************************
                    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;
}

Funcionamento Teórico

Dispositivo Master (Uno)

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.

Dispositivo Slave (Mega)

Ao ser acionado o evento de recebimento, o dispositivo SLAVE (Arduino MEGA) recebe a mensagem enviada pelo dispositivo MASTER e o imprime na Serial.

Explicação do Código

Dispositivo Master

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

Dispositivo Slave

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;
}

Demonstração de funcionamento:

https://blog.eletrogate.com/wp-content/uploads/2022/07/Modo-de-Comunicacao-Mestre-e-Escravo.mp4

Modo de Comunicação Mestre e dois Escravos

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:

Algoritmo para placa Arduino Uno (MASTER)

/******************************************************************************
                    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
}

Algoritmo para placa Arduino Nano (SLAVE)

/******************************************************************************
                    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;
}

Algoritmo para placa Arduino Mega (SLAVE)

/******************************************************************************
                    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;
}

Funcionamento Teórico

Dispositivo Master (Uno)

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;

Dispositivo Slave (Nano)

Ao ser acionado o evento de recebimento, o dispositivo SLAVE (Arduino Nano) recebe a mensagem enviada pelo dispositivo MASTER e o imprime na Serial.

Dispositivo Slave (Mega)

Ao ser acionado o evento de recebimento, o dispositivo SLAVE (Arduino MEGA) recebe a mensagem enviada pelo dispositivo MASTER e o imprime na Serial.

Explicação do Código

Dispositivo Master (Uno)

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
}

Dispositivo Slave (Nano)

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;
}

Dispositivo Slave (Mega)

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;
}

Demonstração de funcionamento:

https://blog.eletrogate.com/wp-content/uploads/2022/07/EQj011LvmI.mp4

Modo de Comunicação Escravo e Mestre com Confirmação de Envio

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:

Algoritmo para placa Arduino Mega (MASTER)

/******************************************************************************
                    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;
}

Algoritmo para placa Arduino Nano (SLAVE)

/******************************************************************************
                    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;
}

Funcionamento Teórico

Dispositivo Master (Mega)

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.

Dispositivo Slave (Nano)

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.

Explicação do Código

Dispositivo Master (Mega)

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

Dispositivo Slave (Nano)

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;
}

Demonstração de funcionamento:

https://blog.eletrogate.com/wp-content/uploads/2022/07/xJmSzEHKap.mp4

Hardware do Projeto

Para realizar o projeto, monte o hardware de acordo com o seguinte esquemático:

Após a montagem, ficou assim:


Software do Projeto

Identificação dos endereços I2C

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.

Algoritmo para placa Arduino Uno (MASTER)

/******************************************************************************
                    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;
}

Algoritmo para placa Arduino Nano (SLAVE)

/******************************************************************************
                    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;
}

Funcionamento Teórico

Dispositivo Master (Uno)

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.

Dispositivo Slave (Nano)

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.


Demonstração de Funcionamento do Projeto

Veja o vídeo abaixo para ver o funcionamento final:

https://blog.eletrogate.com/wp-content/uploads/2022/07/Comunicacao-I2C-entre-Arduinos.mp4

Conclusão

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!


Sobre o Autor


Michel Galvão

Hobbysta em Sistemas Embarcados e IoT. Tem experiência em Automação Residencial e Agrícola.


Eletrogate

19 de agosto de 2022 Atualizado em: 31 mar 2023

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.

Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!

Projetos

Jogo da Velha na TV!

Eletrogate19 de setembro de 2023

Este é um jogo de quebra-cabeça para dois jogadores, identificados como “X” e “O”, que se revezam marcando os espaços em uma área 3 × 3.
Alguma vez na vida você já deve ter jogado este clássico jogo conhecido como Jogo-da-Velha ou Tic-Tac-Toe.

Neste post, você vai aprender a montar e programar uma versão digital deste jogo, com saída de imagem para TV, utilizando apenas alguns componentes eletrônicos básicos, uma placa Arduino UNO e um Teclado Matricial de 16 teclas.

Projetos

Jogo da Velha na TV!

Eletrogate19 de setembro de 2023

Este é um jogo de quebra-cabeça para dois jogadores, identificados como “X” e “O”, que se revezam marcando os espaços em uma área 3 × 3.
Alguma vez na vida você já deve ter jogado este clássico jogo conhecido como Jogo-da-Velha ou Tic-Tac-Toe.

Neste post, você vai aprender a montar e programar uma versão digital deste jogo, com saída de imagem para TV, utilizando apenas alguns componentes eletrônicos básicos, uma placa Arduino UNO e um Teclado Matricial de 16 teclas.

IoT

LittleFS: Alto Desempenho para RP Pico, ESP32 e ESP8266

Eletrogate12 de setembro de 2023

Aprenda neste post, a usar o sistema de arquivos LittleFS, que possui mais desempenho do que o sistema SPIFFS, nas placas Raspberry Pi Pico, ESP32 e ESP8266.

IoT

LittleFS: Alto Desempenho para RP Pico, ESP32 e ESP8266

Eletrogate12 de setembro de 2023

Aprenda neste post, a usar o sistema de arquivos LittleFS, que possui mais desempenho do que o sistema SPIFFS, nas placas Raspberry Pi Pico, ESP32 e ESP8266.

Sensores

Como Utilizar o Módulo Sensor de Cor RGB TCS34725

Eletrogate5 de setembro de 2023

Você já precisou de algum sensor para detectar as cores de objetos? Venha conferir o post de hoje! Nós vamos utilizar o sensor RGB TCS34725.

Sensores

Como Utilizar o Módulo Sensor de Cor RGB TCS34725

Eletrogate5 de setembro de 2023

Você já precisou de algum sensor para detectar as cores de objetos? Venha conferir o post de hoje! Nós vamos utilizar o sensor RGB TCS34725.

Projetos

Controlando o Braço Robótico em MDF via Bluetooth

Eletrogate29 de agosto de 2023 Atualizado em: 01 set 2023

Que tal montar um braço robótico e controlá-lo pelo celular? Entre para dicas de montagem e aprender a controlar servos e conectar sua placa.

Projetos

Controlando o Braço Robótico em MDF via Bluetooth

Eletrogate29 de agosto de 2023 Atualizado em: 01 set 2023

Que tal montar um braço robótico e controlá-lo pelo celular? Entre para dicas de montagem e aprender a controlar servos e conectar sua placa.

Eletrogate Robô

Cadastre-se e fique por
dentro de novidades!

blog-eletrogate-logo-footer

Rua Rio de Janeiro, 441 - Sala 1301
Centro - Belo Horizonte/MG
CEP 30160-041
*Não temos atendimento físico

ANWAR SLEIMAN HACHOUCHE - ME
CNPJ: 18.917.521/0001-73

Atendimento

(31) 3142-3800

[email protected]


Seg a Sex - das 8h às 17h

Institucional

  • Apostilas
  • Quem Somos
  • Privacidade
  • Seja um Redator
  • Trabalhe Conosco

Nos acompanhe

Facebook Instagram Youtube

© ELETROGATE 2023 - Todos os direitos reservados. Termos de uso e Política de privacidade.