Super WiFi Longa Distância do ESP32 LoRa com Arduino IDE



Bastante útil por depurar e testar o seu programa, em função do display que já o acompanha, hoje vamos tratar novamente do ESP32 LoRa, desta vez em um projeto utilizando o sensor BME280. Vocês já sabem que gosto muito deste chip, inclusive pela possibilidade de seu uso em campo. Vamos, então, enviar solicitações utilizando LoRa, executar a leitura da temperatura, pressão e umidade utilizando o sensor BME280, além de enviar resposta à solicitação com os dados lidos.


No nosso projeto, o Master envia uma solicitação ao Slave. O Slave utilza o sensor BME280 para fazer a leitura dos dados, sendo que este mesmo Slave envia para o Master os dados lidos. O Master, então, calcula o tempo da operação e mostra os dados. Tudo isso, faço usando o radio LoRa, que vai longe, como comprovado em um teste que fizemos que chegamos ao alcance de 6,5 km.


  Onde encontrar este ESP32 LoRa: https://bit.ly/2JpAi7u


Comunicação


1 - O Master envia um pacote indicando que deseja receber os dados do Slave
2 - O Slave recebe e verifica este pacote
3 - O Slave envia de volta um pacote com os dados lidos do sensor BME280
4 - O Master recebe, verifica o pacote e exibe os dados


Heltec WiFi LoRa 32 Pinout



BME280

Sensor de temperatura, pressão e umidade.



Montagem



Biblioteca BME280

Na IDE do Arduino vá em Sketch->Incluir Biblioteca->Gerenciar Bibliotecas...
Procure por BME280 e instale Adafruit BME280 Library



Biblioteca Adafruit Unified Sensor

Na IDE do Arduino vá em Sketch->Incluir Biblioteca->Gerenciar Bibliotecas...
Procure por adafruit sensor based libraries e instale Adafruit Unified Sensor



Modificar pinagem I2C do WiFi LoRa 32

Preciso contar para vocês que, na primeira vez que compilei o BME280 no ESP32, não deu certo. Então, veja só essa dica: você tem que modificar um .h de dentro do compilador do arduino. Essa é uma questão que não se descobre rapidamente, então quero te explicar aqui o que você deve fazer.
Em C:\Users\<SEU_USUARIO>\Documents\Arduino\hardware\heltec\esp32\variants\wifi_lora_32\pins_arduino.h a Heltec colocou o SAD e o SCL, no pinos 21 e 22, respectivamente. Porém, a lib da Adafruit não aceita esses pinos. Qual a biblioteca aceita: o 4 e o 15. Essa alteração, portanto, é muito importante.

Portanto:
Abra o arquivo:
C:\Users\<SEU_USUARIO>\Documents\Arduino\hardware\heltec\esp32\variants\wifi_lora_32\pins_arduino.h
Altere os pinos SDA para 4, e o pino SCL para 15.




Código fonte

Esse código fonte é o mesmo que utilizei no vídeo: ESP32 LoRa comArduino IDE Send e Receive TX RX. Eu apenas o modifiquei para o BME280.


LoRaSendReceiveBME280.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, bem como o retorno destes para o Master. Estruturamos ainda os dados do sensor e apontamos a 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 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=";

//Estrutura com os dados do sensor
typedef struct {
  double temperature;
  double pressure;
  double humidity;
}Data;

//Variável para controlar o display
SSD1306 display(0x3c, SDA, SCL);



LoRaSendReceiveBME280.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_16);
  display.setTextAlignment(TEXT_ALIGN_LEFT);
}


LoRaSendReceiveBME280.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 – setup

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. Ainda, chamamos as configurações iniciais do display e do LoRa.

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

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 – send

Inicializamos o pacote e enviamos o que está contido em “GETDATA”, para posteriormente finalizar e enviar o pacote.

void send(){
  //Inicializa o pacote
  LoRa.beginPacket();
  //Envia o que está contido em "GETDATA"
  LoRa.print(GETDATA);
  //Finaliza e envia o pacote
  LoRa.endPacket();
}


Master.ino – receive

Nesta etapa, verificamos se o pacote tem o tamanho mínimo de caracteres que esperamos e armazenamos uma string. Ainda analisamos se o cabeçalho é o que esperamos, partimos para a leitura dos dados e os exibimos no display.

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
    for(int i=0; i<SETDATA.length(); i++){
      received += (char) LoRa.read();
    }

    //Se o cabeçalho é o que esperamos
    if(received.equals(SETDATA)){
      //Fazemos a leitura dos dados
      Data data;
      LoRa.readBytes((uint8_t*)&data, sizeof(data));
      //Mostramos os dados no display
      showData(data);
    }
  }
}


Master.ino – showData

Por fim, mostramos o tempo que o Master levou para criar o pacote, enviar, o Slave receber, fazer a leitura, criar um novo pacote e enviá-lo ao Master, que o recebe e faz a leitura. Este é impresso no display.

void showData(Data data){
  //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, String(data.temperature) + " C");
  display.drawString(0, 16, String(data.pressure) + " Pa");
  display.drawString(0, 32, String(data.humidity) + "%");
  display.drawString(0, 48, 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.  Incluímos as bibliotecas e apontamos a responsável pela leitura da temperatura, pressão e umidade.

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

#include <adafruit_sensor.h>
#include <adafruit_bme280.h>


//Responsável pela leitura da temperatura, pressão e umidade
Adafruit_BME280 bme; 


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();

  //0x76 se pino SDO do sensor estiver no GND
  //0x77 se pino SDO do sensor estiver no 3.3v 
  if (!bme.begin(0x76))
  {
    display.clear();
    display.drawString(0, 0, "Sensor não encontrado");
    display.display();
    while(1);
  }

  display.clear();
  display.drawString(0, 0, "Slave esperando...");
  display.display();
}


Slave.ino - Loop

Assim como no Master, nesta parte do Loop do Slave, verificamos se o mesmo tem a quantidade de caracteres esperada e armazenamos os dados em uma String. Ainda, simulamos a leitura dos dados. Criamos o pacote, finalizamos e enviamos. Por fim, exibimos as informações no display.

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

    if(received.equals(GETDATA))
    {
      //Faz a leitura dos dados
      Data data = readData();
      Serial.println("Criando pacote para envio");
      //Cria o pacote para envio
      LoRa.beginPacket();
      LoRa.print(SETDATA);
      LoRa.write((uint8_t*)&data, sizeof(data));
      //Finaliza e envia o pacote
      LoRa.endPacket();
      showSentData(data);
    }
  }
}


Slave.ino – readData

Nesta parte tratamos da função onde se faz a leitura dos dados.

//Função onde se faz a leitura dos dados
Data readData()
{
  Data data;
  data.temperature = bme.readTemperature();
  data.pressure = bme.readPressure();
  data.humidity = bme.readHumidity();
  return data;
}


Slave.ino – showSentData

Enfim, exibidos os dados no display.

void showSentData(Data data)
{
  //Mostra no display
  display.clear();
  display.drawString(0, 0, "Enviou:");
  display.drawString(0, 16,  String(data.temperature) + " C");
  display.drawString(0, 32, String(data.pressure) + " Pa");
  display.drawString(0, 48, String(data.humidity) + "%");
  display.display();
}

#endif


Faça o download dos arquivos:



Onde encontrar este ESP32 LoRa: https://bit.ly/2JpAi7u





Nenhum comentário:

Tecnologia do Blogger.