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.
Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!