Que tal criar seu próprio
rastreador? Pois, hoje vou te apresentar o A9G, esse modem GPRS que já tem
embutido o GPS. E isso é muito bom, pois estamos tratando de duas coisas que justamente
precisamos utilizar juntas. Neste vídeo, então, apresento um exemplo de
utilização do GPRS/GPS A9G com comunicação com o ESP32 LoRa utilizando UART.
RECURSOS USADOS
- ESP32 WiFi LoRa
- A9G Pudding Devboard
- Push button
- Resistor 10K ohm
- Protoboard
- Jumpers
CASAN: Companhia Catarinense de Águas e Saneamento
Aproveitando que estamos
falando de GPRS, destaco neste vídeo uma experiência que tive em Florianópolis,
onde conheci a equipe de engenheiros da Casan, da área de telemetria, com um
projeto bastante grande de monitoramento e operação dos sistemas com a Internet
das Coisas.
Exemplo de IoT com GPRS : CASAN
Superintendência Regional
Metropolitana que abrange as cidades da Grande Florianópolis e proximidades:
- 430 telas ;
- 9.770 datapoints (endpoints);
- 239 usuários que acessam este sistema;
Unidade de Recuperação Ambiental
PINOUT A9G PUDDING DEVBOARD
PINOUT ESP32 WIFI LORA
MONTAGEM
BIBLIOTECAS NECESSÁRIAS
Biblioteca do display SSD1306
Biblioteca do GPS
CÓDIGO
Fluxograma
Declarações e Variáveis
#include <TinyGPS++.h> // Bibliteca com as funções de GPS #include <HardwareSerial.h> // Biblioteca Hardware Serial #include "display/DisplayLoRa.h" // Biblioteca com as funções do display do ESP LoRa // Objeto HardwareSerial. Comunicação com o módulo A9G HardwareSerial A9G(1); // Objeto com as funções de GPS TinyGPSPlus gps; // Pinos de comunicação Serial com o módulo A9G const int RX_PIN = 23; const int TX_PIN = 22; // Pino do botão que configura o módulo caso pressionado durante o boot const int btnConf = 37; // Objeto do display DisplayLoRa Display; // Variáveis auxiliares de contegem de tempo long prevMillis; bool updateMillis = true; // Assinatura de funções declaradas abaixo do loop void displayInfo(); void applyTimeZone(int8_t delta, uint8_t *day, uint8_t *month, uint16_t *year, uint8_t *hours); uint8_t getMonthLength(uint8_t month, uint16_t year);
Setup
void setup() { // Inicia comunicação Serial com o módulo. A velocidade padrão é 115200 A9G.begin(115200, SERIAL_8N1, RX_PIN, TX_PIN); // Inicia a Serial que será usada como debug Serial.begin(115200); // Inicia o display Display.begin(); // Seta o pino do botão como entrada pinMode(btnConf, INPUT); // Exibe mensagem de teste na serial e no display printMsg("Test display", true);
// Aguarda 5 segundos, se o botão estiver pressionado nesse tempo, configuramos o módulo. updateMillis = true; while(!timeout(5000, &prevMillis, &updateMillis)) { if(digitalRead(btnConf)) { A9config(); break; } } // Ignora as mensagens iniciais while(A9G.available() > 0) A9G.read(); }
Loop
void loop() { // Se existirem dados a serem lidos, efetuamos a leitura e exibimos no display while(A9G.available() > 0) if(gps.encode(A9G.read())) displayInfo(); }
displayInfo
// Função que exibe os dados de GPS no display void displayInfo() { char location[30], date[30], time[30]; // Verificamos se os dados de GPS são válidos if(gps.location.isValid()) // Se sim, atribuimos os valores de latitude e longitude para a variável location, separando-os por vírgula sprintf(location, "%.6f,%.6f", gps.location.lat(), gps.location.lng()); else // Se não, indicamos valor inválido strcpy(location, "INVALID");
// Verificamos se os dados de data e tempo são válidos if(gps.date.isValid() && gps.time.isValid()) { uint8_t day, month, hours; uint16_t year; // Atribuímos os valores de dia, mes, ano e hora para as variáveis day = gps.date.day(); month = gps.date.month(); year = gps.date.year(); hours = gps.time.hour(); // Ajustamos o horário UTC-3 (Tempo Universal Coordenado) applyTimeZone(-3, &day, &month, &year, &hours); // Atribuímos os valores para a variável date sprintf(date, "%02d/%02d/%02d", day, month, year); // Atribuímos os valores para a variável time sprintf(time, "%02d:%02d:%02d", hours, gps.time.minute(), gps.time.second()); } else { // Atribuímos uma mensagem de dados inválidos, se este for o caso strcpy(date, "INVALID"); strcpy(time, "INVALID"); }
// Exibimos na serial e no display os valores obtidos printMsg("Location: ", true); printMsg(String(location), false); printMsg("Date: "+ String(date), false); printMsg("Time: "+ String(time), false); }
applyTimeZone
// Função que ajusta o horário UTC void applyTimeZone(int8_t delta, uint8_t *day, uint8_t *month, uint16_t *year, uint8_t *hours) { if(delta < 0) { if(int8_t(*hours) < -delta) { *hours += 24+delta; if(--*day == 0) { if(--*month == 0) { *month = 12; *year--; } *day = getMonthLength(*month, *year); } } else *hours += delta; }
else { *hours += delta; if(*hours > 23) { *hours -= 24; if(++*day > getMonthLength(*month, *year)) { *day = 1; if(++*month > 12) { *month = 1; *year++; } } } } }
getMonthLength
// Função auxiliar usada em "applyTimeZone", que obtém a qtde de dias no mês uint8_t getMonthLength(uint8_t month, uint16_t year) { if(month == 2) if(year%4 == 0) return 29; else return 28; else if((month == 4) || (month == 6) || (month == 9) || (month == 11)) return 30; else return 31; }
A9config
// Função que habilita e inicia o GPS void A9config() { String response = ""; // Verifica se o modulo está funcionando while(response.indexOf("OK")<0) { printMsg("Enviando AT", true); if(!sendToA9G("AT", &response)) printMsg("Sem resposta...", true); else printMsg("Resposta: "+response, true); } printMsg("Modulo A9G OK", true);
// Habilita o GPS if(!sendToA9G("AT+GPS=1", &response)) { printMsg("AT+GPS=1 erro", true); while(true); } // Exibe OK ou erro if(response.indexOf("OK")<=0) printMsg("Erro ao receber ok, resposta: "+response, true); else printMsg("AT+GPS=1 OK", true); // Inicia o GPS, a partir desse momento o A9G nos enviará os dados de GPS de tempo e tempo if(!sendToA9G("AT+GPSRD=1", &response)) printMsg("AT+GPSRD=1 erro", true); // Exibe OK ou erro if(response.indexOf("OK")<=0) printMsg("Erro ao receber ok, resposta: "+response, true); else printMsg("AT+GPSRD=1 OK", true); }
sendToA9G
// Função que envia um comando para o módulo e aguarda um tempo de resposta bool sendToA9G(String cmd, String *response, int timeoutWait = 3000) { *response = ""; // Envia o comando pro módulo A9G.println(cmd); // Aguarda resposta do módulo updateMillis = true; while(!timeout(timeoutWait, &prevMillis, &updateMillis)) { if(A9G.available()) { *response = A9G.readString(); return true; } } return false; }
printMsg e timeout
// Exibimos na serial e no display a String 'msg' void printMsg(String msg, bool clear) { Serial.println(msg); Display.println(msg, clear); } // Função que aguarda um tempo sem que seja necessário a utilização do delay bool timeout(const int DELAY, long *millisAnterior, bool *flag) { if(*flag) { *millisAnterior = millis(); *flag = false; } if((*millisAnterior + DELAY) < millis()) { *flag = true; return true; } return false; }
2 Comentários
Através do ESP32 posso transmitir dados de pressão de um sistema de abastecimento de água?
ResponderExcluirSim
Excluir