Esp32 LoRa com Arduino IDE: Send e Receive TX RX



Seguindo sugestões de seguidores do meu canal no YouTube, hoje, novamente, vamos falar sobre o ESP32 LoRa, mas, desta vez, sobre o envio e recebimento de dados por um mesmo dispositivo. Sendo assim, um ESP32 LoRa, o Master, enviará um pacote avisando que quer receber os dados, enquanto um outro dispositivo, o Slave, ficará aguardando o comando para enviar os dados de volta para o Master. Ou seja, diferentemente de outros vídeos que já fiz com um ESP32 LoRa como Sender e outro como Receiver, hoje teremos os dispositivos, tanto o Master quanto o Slave, enviando e recebendo dados.

ESP32 LORA

Esquema de funcionamento


LoRa ESP32 Pinout

Pinout do ESP32 LoRA

Deixo aqui o PinOut do ESP32 LoRa, lembrando que, sempre que utilizamos este modelo, este já está usando as suas portas SPI. Então, na imagem, onde coloquei as setas vermelhas estão os pinos que já estão sendo utilizados pelo chip LoRa, que fica abaixo do display.


Comunicação

Mostro aqui o esquema de funcionamento do nosso projeto, no qual o Master envia um pacote de dados ao Slave, que envia de volta essas informações ao Master, ciclo que segue se repetindo em um loop infinito.

Esquema de funcionamento do projeto Master/Slave


Demonstração

Vejo no vídeo os dois chips trocando informações.

Na nossa montagem temos os dois chips trocando informações


Código Fonte

LoRaSendReceive.ino
De início, vamos incluir as bibliotecas e definir os destinos dos GPIOs, além da frequência do rádio. Ainda, vamos criar constantes para informar ao Slave sobre os trabalhos com os dados. Temos ainda nesta etapa uma variável para controlar o display.

#include <SPI.h>
#include <LoRa.h>
#include <Wire.h>
#include <SSD1306.h>

//Deixe esta linha descomentada para compilar o Master
//Comente ou remova para compilar o Slave
// #define MASTER

#define SCK 5   // GPIO5  SCK
#define MISO 19 // GPIO19 MISO
#define MOSI 27 // GPIO27 MOSI
#define SS 18   // GPIO18 CS
#define RST 14  // GPIO14 RESET
#define DI00 26 // GPIO26 IRQ(Interrupt Request)

#define BAND 433E6 //Frequência do radio - exemplo : 433E6, 868E6, 915E6

//Constante para informar ao Slave que queremos os dados
const String GETDATA = "getdata";
//Constante que o Slave retorna junto com os dados para o Master
const String SETDATA = "setdata=";

//Variável para controlar o display
SSD1306 display(0x3c, 4, 15);


LoRaSendReceive.ino – setupDisplay
Neste primeiro Setup, vamos atuar na configuração do display.

void setupDisplay(){
  //O estado do GPIO16 é utilizado para controlar o display OLED
  pinMode(16, OUTPUT);
  //Reseta as configurações do display OLED
  digitalWrite(16, LOW);
  //Para o OLED permanecer ligado, o GPIO16 deve permanecer HIGH
  //Deve estar em HIGH antes de chamar o display.init() e fazer as demais configurações,
  //não inverta a ordem
  digitalWrite(16, HIGH);

  //Configurações do display
  display.init();
  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_10);
  display.setTextAlignment(TEXT_ALIGN_LEFT);
}


LoRaSendReceive.ino – setupLoRa
Aqui, vamos tratar das configurações iniciais do LoRa.

//Configurações iniciais do LoRa
void setupLoRa(){ 
  //Inicializa a comunicação
  SPI.begin(SCK, MISO, MOSI, SS);
  LoRa.setPins(SS, RST, DI00);

  //Inicializa o LoRa
  if (!LoRa.begin(BAND, true)){
    //Se não conseguiu inicializar, mostra uma mensagem no display
    display.clear();
    display.drawString(0, 0, "Erro ao inicializar o LoRa!");
    display.display();
    while (1);
  }

  //Ativa o crc
  LoRa.enableCrc();
  //Ativa o recebimento de pacotes
  LoRa.receive();
}


Master.ino

Fazemos nesta parte as configurações que envolvem o Master, estas sobre a compilação, o intervalo entre envios, bem como o tempo do último envio. Importante destacar que, embora eu exiba no PDF um intervalo entre envios de 1000, na verdade utilizei 500, como você pode ver no código.

//Compila apenas se MASTER estiver definido no arquivo principal
#ifdef MASTER

//Intervalo entre os envios
#define INTERVAL 500

//Tempo do último envio
long lastSendTime = 0;


Master.ino – setup
Aqui, chamamos as configurações iniciais do display e do LoRa.

void setup(){
  Serial.begin(115200);
  //Chama a configuração inicial do display
  setupDisplay();
  //Chama a configuração inicial do LoRa
  setupLoRa();

  display.clear();
  display.drawString(0, 0, "Master");
  display.display();
}

Master.ino – loop
Neste Loop, definimos o envio do pacote para informar ao Slave o desejo de receber dados e ainda verificamos se existem pacotes a serem recebidos.

void loop(){
  //Se passou o tempo definido em INTERVAL desde o último envio
  if (millis() - lastSendTime > INTERVAL){
    //Marcamos o tempo que ocorreu o último envio
    lastSendTime = millis();
    //Envia o pacote para informar ao Slave que queremos receber os dados
    send();
  }

  //Verificamos se há pacotes para recebermos
  receive();
}

Master.ino - receive 1/2
Executamos uma tentativa de leitura do pacote, verificamos se o mesmo tem tamanho mínimo de caracteres esperado, armazenamos os dados em uma string, a qual deve possuir o que está contido em “SETDATA”.

void receive(){
  //Tentamos ler o pacote
  int packetSize = LoRa.parsePacket();
  
  //Verificamos se o pacote tem o tamanho mínimo de caracteres que esperamos
  if (packetSize > SETDATA.length()){
    String received = "";
    //Armazena os dados do pacote em uma string
    while(LoRa.available()){
      received += (char) LoRa.read();
    }
    //Verifica se a string possui o que está contido em "SETDATA"
    int index = received.indexOf(SETDATA);

Master.ino - receive 2/2
Agora, recuperamos a String que está após o "SETDATA", que, no caso, se trata dos dados de nosso interesse. Analisamos ainda o tempo que demorou para o Master criar e enviar o pacote e quanto tempo foi para o Slave receber, fazer a leitura, criar um novo pacote, enviá-lo e este ser novamente recebido pelo Master. Exibimos, então, no display, os dados e o tempo que a operação exigiu.

if(index >= 0){
      //Recuperamos a string que está após o "SETDATA",
      //que no caso serão os dados de nosso interesse
      String data = received.substring(SETDATA.length());
      //Tempo que demorou para o Master criar o pacote, enviar o pacote,
      //o Slave receber, fazer a leitura, criar um novo pacote, enviá-lo
      //e o Master receber e ler
      String waiting = String(millis() - lastSendTime);
      //Mostra no display os dados e o tempo que a operação demorou
      display.clear();
      display.drawString(0, 0, "Recebeu: " + data);
      display.drawString(0, 10, "Tempo: " + waiting + "ms");
      display.display();
    }
  }
}

#endif

Slave.ino

Iniciando o código do Slave, compilamos apenas se o Master não estiver definido no arquivo principal. Temos aqui o Contador que irá atuar como os dados que o Slave irá enviar.

//Compila apenas se MASTER não estiver definido no arquivo principal
#ifndef MASTER

//Contador que irá servir como o dados que o Slave irá enviar
int count = 0;

Slave.ino – Setup
No Setup do Slave, chamamos as configurações iniciais do display e do LoRa.

void setup(){
    Serial.begin(115200);
    //Chama a configuração inicial do display
    setupDisplay();
    //Chama a configuração inicial do LoRa
    setupLoRa();
    display.clear();
    display.drawString(0, 0, "Slave esperando...");
    display.display();
}


Slave.ino - Loop 1/2
Assim como no Master, nesta parte do Loop do Slave executamos uma tentativa de leitura do pacote, verificamos se o mesmo tem a quantidade de caracteres esperada e armazenamos os dados em uma String.

void loop(){
  //Tenta ler o pacote
  int packetSize = LoRa.parsePacket();

  //Verifica se o pacote possui a quantidade de caracteres que esperamos
  if (packetSize == GETDATA.length()){
    String received = "";

    //Armazena os dados do pacote em uma string
    while(LoRa.available()){
      received += (char) LoRa.read();
    }

Slave.ino - Loop 2/2
Agora, simulamos a leitura dos dados. Criamos o pacote, finalizamos e enviamos. Por fim, exibimos as informações no display.

if(received.equals(GETDATA)){
      //Simula a leitura dos dados
      String data = readData();
      Serial.println("Criando pacote para envio");
      //Cria o pacote para envio
      LoRa.beginPacket();
      LoRa.print(SETDATA + data);
      //Finaliza e envia o pacote
      LoRa.endPacket();
      //Mostra no display
      display.clear();
      display.drawString(0, 0, "Enviou: " + String(data));
      display.display();
    }
  }
}

Para finalizar, temos aqui uma função para leitura dos dados que queira enviar. Poderia ser o valor lido por algum sensor, por exemplo. Aqui, no nosso projeto, vamos enviar apenas um contador para testes, mas você pode alterar a função para fazer a leitura dos dados de sua preferência.

//Função onde se faz a leitura dos dados que queira enviar
//Poderia ser o valor lido por algum sensor por exemplo
//Aqui vamos enviar apenas um contador para testes
//mas você pode alterar a função para fazer a leitura de algum sensor
String readData(){
  return String(count++);
}

#endif



Faça o download dos arquivos:




Um comentário:

  1. Fernando... Quando tento compilar o código exibe o seguinte erro.:


    C:\Users\Shaka\Desktop\LoRaSendReceive\LoRaSendReceive.ino: In function 'void setupLoRa()':

    LoRaSendReceive:51: error: no matching function for call to 'LoRaClass::begin(int, bool)'

    if (!LoRa.begin(BAND, true)){

    ^

    In file included from C:\Users\Shaka\Desktop\LoRaSendReceive\LoRaSendReceive.ino:2:0:

    C:\Users\Shaka\Documents\Arduino\libraries\LoRa\src/LoRa.h:31:7: note: candidate: int LoRaClass::begin(long int)

    int begin(long frequency);

    ^

    C:\Users\Shaka\Documents\Arduino\libraries\LoRa\src/LoRa.h:31:7: note: candidate expects 1 argument, 2 provided

    exit status 1
    no matching function for call to 'LoRaClass::begin(int, bool)'

    ResponderExcluir

Tecnologia do Blogger.