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.
LoRa ESP32 Pinout
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.
Demonstração
Vejo no vídeo 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:
11 Comentários
Fernando... Quando tento compilar o código exibe o seguinte erro.:
ResponderExcluirC:\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)'
Nobre Fernando, excelente videoaula.
ResponderExcluirEstou com a mesma dificuldade do colega Hugo acima. Ao tentar compilar recebo a mesma mensagem de erro que a função Lora.begin() aguarda 1 argumento e estamos passando dois (no caso a banda e o 'true').
Como podemos resolver ?
Obrigado. Abraço
Excelente sequência de vídeos Fernando, material muito bem feito, de grande ajuda!
ResponderExcluirAo final do vídeo você cita uma outra aula fazendo um experimento com multi-client, você já postou essa aula? Não consegui encontrar aqui, gostaria de vê-la!
Obrigado, Abraço!
Bom dia Fernando. Muito bom o vídeo e toda a explicação. Já publicou algum vídeo parecido, mas em vez de ser só entre dois esp32 ser entre mais? Ou seja um master e vários Alavés?
ResponderExcluirCaro Hugo, boa noite.
ResponderExcluirAconteceu o mesmo comigo, alguma solução ?
Caro Hirata Shibumi,
ResponderExcluirEstou com o mesmo erro ao compilar o código. Conseguiu resolver? Alguma dica? Obrigado
Para o erro retratado acima (!LoRa.begin(BAND, true)), basta remover o parâmetro true que funciona, ficando assim (!LoRa.begin(BAND))
ResponderExcluirBrigado
ExcluirOlá. O meu dá o mesmo erro deixando (!Lora.begin(BAND)). Nem havia colocado o true. Alguma sugestão do que fazer?
ExcluirFenando averta o ino de post pois está dando erro no programas ! E qual seria a finalidade na linha 50 da palavra true pois esta palavra esta gerando erro!!!
ResponderExcluirif (!LoRa.begin(BAND,true))
Alguem tem a função send(); ?
ResponderExcluirerror: 'send' was not declared in this scope
send();