Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*********
- target : Heltec WiFi Lora 32(V2)
- LCD2004 display on I2C
- buttons * 2
- voltage regulator LM2596D
- GPS ublox neo8m + antenna
- provides : satellites number used and viewed
- speed in knots and kilometers/hour
- cap in orientation and degrees
- latitude in decimal degrees and degrees minutes seconds
- longitude in decimal degrees and degrees minutes seconds
- battery voltage
- UTC date time by GPS
- OTA examples : https://www.aranacorp.com/fr/programmer-un-esp32-via-wifi-avec-lide-arduino-ota/
- https://randomnerdtutorials.com/esp32-over-the-air-ota-programming/
- https://randomnerdtutorials.com/esp32-ota-over-the-air-arduino/
- SPIFFS examples : https://randomnerdtutorials.com/install-esp32-filesystem-uploader-arduino-ide/
- https://www.programmingelectronics.com/spiffs-esp32/
- TinyGPS+ explanations : https://arduiniana.org/2013/09/tinygps-a-new-view-of-global-positioning/
- *********/
- // Import required libraries
- // if the library is global use <>
- // if the library is local use ""
- #include <ArduinoOTA.h>
- #include <ESPmDNS.h>
- #include <rom/ets_sys.h>
- #include <heltec.h> // include <Arduino.h>, <SPI.h>, <Wire.h>
- #include <LiquidCrystal_I2C.h>
- #include <SPIFFS.h>
- #include <time.h>
- #include <HT_TinyGPS++.h> // same as TinyGPSPlus
- #include <WiFi.h>
- #include <WiFiUdp.h>
- #include <Wire.h>
- #define BAND 868E6 //you can set band here directly,e.g. 868E6,915E6
- #define button0Pin 0 // GPIO 0 or PRG button
- #define batteryPin 37 // read battery tension 37 or A44.05/1.25
- #define batteryCoeff 0.0029 // 0.0029053 empirical coefficient from analog to tension. battery tension divided par analog value
- #define startPin 12 // GPIO 12
- #define sleepPin 13 // GPIO 13
- //#define touchPin 14 // GPIO 14
- //#define Treshold -1 // touchpad sensibility
- #define VextControlPin 21 // GPIO 21
- #define BattReadLoop 10
- #define BuiltInLed 25 // GPIO 25
- #define tempo 2000 // 2 seconds
- // HardwareSerial on passe les GPIO !
- #define rx0GPIO 3 // pin 34
- #define tx0GPIO 1 // pin 35
- //#define rx1GPIO 14 // not existing on Heltec WiFi Lora 32(V2), use HardweSerial if needed
- //#define tx1GPIO 12 // not existing on Heltec WiFi Lora 32(V2), use HardweSerial if needed
- #define rx2GPIO 16 // pin 27
- #define tx2GPIO 17 // pin 28
- #define baudrateSerial 38400 // vitesse communication Arduino - PC
- #define baudrateSerial1 38400
- #define baudrateSerial2 38400
- #define GpsPort2 Serial2
- #define LAT 0
- #define LNG 1
- #define USING_SPIFFS // else using SD Card
- #define SDA_GPIO 4
- #define SCL_GPIO 15
- #define numCols 20 // for lcd
- #define numRows 4
- LiquidCrystal_I2C lcd(0x27, numCols, numRows); // use this for I2C LCD.
- // WIFI_MODE_NULL
- // WIFI_MODE_STA // WiFi station mode
- // WIFI_MODE_AP // WiFi soft-AP mode
- // WIFI_MODE_APSTA // WiFi station + soft-AP mode
- #define AP_MODE
- #if defined AP_MODE
- #define OCTET3 4
- IPAddress localIP(192,168,OCTET3,10);
- IPAddress subnetMaskIP(255,255,255,0);
- IPAddress gatewayIP(192,168,OCTET3,99);
- IPAddress broadcastIP;
- IPAddress dhcp_startIP(192,168,OCTET3,11);
- #else
- IPAddress localIP, subnetMaskIP, gatewayIP, broadcastIP;
- #endif
- #define UDP_PORT 2010 // 2010 used by ESP32_AIS_Nmea, but no problem
- bool bLCDDisplay = false,
- bDisplayFlap = true,
- bWeHaveAFix = false,
- bSpeed = false;
- uint32_t newMillis, oldMillis, oldMillis_x;
- // objects delcarations
- NetworkUDP udp; //The udp library class
- TinyGPSPlus GPS;
- TinyGPSCustom UsedSats(GPS, "GNGNS", 7); // Fix data total number of satellites in use 00-99
- TinyGPSCustom GAViewedSats(GPS, "GAGSV", 3); // Galileo EU total number of satellites in view
- TinyGPSCustom GBViewedSats(GPS, "GBGSV", 3); // Beidou CH total number of satellites in view
- TinyGPSCustom GLViewedSats(GPS, "GLGSV", 3); // Glonass RU total number of satellites in view
- TinyGPSCustom GPViewedSats(GPS, "GPGSV", 3); // GPS USA total number of satellites in view
- // function prototype declarations
- String DD_to_DMS(float fValue);
- String * DecimalDegrees_to_DegreesMinutesSeconds(float fLat, float fLng);
- void Display_Init(void);
- void DisplayIMessage(String sMessage, bool bClear, bool bCRLN);
- void OTA_Init(void);
- void Storage_Init(void);
- void WiFi_Init(void);
- // end declarations
- void IRAM_ATTR onSleepButtonEvent() {
- esp_deep_sleep_start();
- }
- void setup() {
- Heltec.begin(false /*DisplayEnable Enable*/, false /*LoRa Enable*/, true /*Serial Enable*/, false /*LoRa use PABOOST*/, BAND /*LoRa RF working band*/);
- Wire.begin(SDA_GPIO, SCL_GPIO); // not started by Heltec.begin(true) so it's needed
- pinMode(sleepPin, INPUT_PULLDOWN); // GPIO13
- attachInterrupt(digitalPinToInterrupt(sleepPin), onSleepButtonEvent, FALLING);
- // Configure le GPIO x comme source de réveil quand la tension vaut 3.3V
- // esp_sleep_enable_ext0_wakeup(GPIO_NUM_12, HIGH); // normal, un seul GPIO
- pinMode(startPin, INPUT_PULLDOWN); // GPIO12
- esp_sleep_enable_ext0_wakeup((gpio_num_t)startPin, HIGH); // alternative, un seul GPIO
- // esp_sleep_enable_ext1_wakeup(0x1000, ESP_EXT1_WAKEUP_ANY_HIGH); // 2^12 = 0x1000 . si plusieurs GPIO 2^GPIOn1 + 2*^GPIOn1 + 2^GPIOnx >> hex
- Serial.begin(baudrateSerial); // Serial0
- GpsPort2.begin(baudrateSerial2, SERIAL_8N1, rx2GPIO, tx2GPIO); // GPS connection
- Display_Init();
- WiFi_Init();
- OTA_Init();
- while (GpsPort2.available() > 0)
- GPS.encode(GpsPort2.read());
- if (GPS.charsProcessed() < 256)
- DisplayIMessage("GPS not detected", false, true);
- else
- DisplayIMessage("GPS detected", false, true);
- Storage_Init();
- pinMode(VextControlPin, OUTPUT);
- digitalWrite(VextControlPin, LOW); // LOW to have 3.3V on pins 3 & 4
- pinMode(batteryPin, INPUT);
- pinMode(BuiltInLed, OUTPUT);
- digitalWrite(BuiltInLed, LOW); // ON after Wifi connection so I set it OFF
- oldMillis = oldMillis_x = millis();
- }
- void loop() {
- static int iUsedSats, iViewedSats;
- static String receivedString;
- static float fLat, fLng, fCourse, fbatteryVoltage;
- static char sBuffer0[16], sBufferCoord[33], dtDateTime[21];
- String * sDMS; // array of String returned from called function
- ArduinoOTA.handle();
- if (GpsPort2.available() > 0) {
- receivedString = GpsPort2.readStringUntil('\n');
- Serial.println(receivedString);
- udp.beginPacket(broadcastIP, UDP_PORT);
- udp.printf(receivedString.c_str());
- udp.endPacket();
- for (int i=0; i < receivedString.length(); i++ )
- GPS.encode(receivedString[i]); // (GpsPort2.read());
- }
- newMillis = millis();
- if (newMillis > oldMillis + tempo) {
- oldMillis = newMillis;
- fbatteryVoltage = 0;
- for (int i = 0; i < BattReadLoop; i++) {
- fbatteryVoltage += analogRead(batteryPin);
- delay(6);
- }
- fbatteryVoltage = fbatteryVoltage * batteryCoeff / BattReadLoop;
- fLat = GPS.location.lat();
- fLng = GPS.location.lng();
- iUsedSats = atoi(UsedSats.value());
- iViewedSats = atoi(GAViewedSats.value()) +
- atoi(GBViewedSats.value()) +
- atoi(GLViewedSats.value()) +
- atoi(GPViewedSats.value());
- if (iUsedSats < 3 || min(fLat, fLng) == 0) {
- lcd.clear();
- sprintf(sBuffer0,"Sat.%3d/%2d ", iUsedSats, iViewedSats);
- lcd.setCursor(0, 0); lcd.print(sBuffer0);
- lcd.setCursor(0, 3); lcd.print(String(fbatteryVoltage, 3) + "v ");
- bWeHaveAFix = false;
- }
- else
- bWeHaveAFix = true;
- lcd.setCursor(0, 1); lcd.print("LAT");
- lcd.setCursor(0, 2); lcd.print("LNG");
- // to have the degree caracter https://www.letscontrolit.com/forum/viewtopic.php?t=2368
- fCourse = GPS.course.isUpdated() ? GPS.course.deg() : 0;
- sprintf(sBuffer0,"%3s %03.0f%c", GPS.cardinal(fCourse), fCourse, byte(223));
- lcd.setCursor(12, 0); lcd.print(sBuffer0);
- if (bWeHaveAFix && bDisplayFlap) {
- sprintf(sBufferCoord, "%+012.7f DD", fLat); // https://cplusplus.com/reference/cstdio/printf/
- lcd.setCursor(5, 1); lcd.print(sBufferCoord);
- sprintf(sBufferCoord, "%+012.7f DD", fLng);
- lcd.setCursor(5, 2); lcd.print(sBufferCoord);
- sprintf(dtDateTime, "%02d-%02d-%02d %02d:%02d:%02dutc", GPS.date.year()-2000, GPS.date.month(), GPS.date.day(),
- GPS.time.hour(), GPS.time.minute(), GPS.time.second());
- lcd.setCursor(0, 3); lcd.print(dtDateTime);
- }
- else if (bWeHaveAFix && !bDisplayFlap) {
- if (bSpeed)
- sprintf(sBuffer0,"km/h %6.2f", (GPS.speed.isUpdated() ? GPS.speed.kmph() : 0));
- else
- sprintf(sBuffer0,"kn %6.2f", (GPS.speed.isUpdated() ? GPS.speed.knots() : 0));
- lcd.setCursor(0, 0); lcd.print(sBuffer0);
- bSpeed = !bSpeed;
- sDMS = DecimalDegrees_to_DegreesMinutesSeconds(fLat, fLng);
- lcd.setCursor(5, 1); lcd.print(sDMS[LAT]);
- lcd.setCursor(5, 2); lcd.print(sDMS[LNG]);
- lcd.setCursor(0, 3); lcd.print(String(fbatteryVoltage, 3) + "v ");
- sprintf(dtDateTime, "%02d:%02d:%02dutc", GPS.time.hour(), GPS.time.minute(), GPS.time.second());
- lcd.setCursor(9, 3); lcd.print(dtDateTime);
- }
- bDisplayFlap = !bDisplayFlap;
- }
- if (newMillis > oldMillis_x + (tempo * 5.5)) {
- oldMillis_x = newMillis;
- sprintf(sBuffer0,"Sat.%3d/%2d ", iUsedSats, iViewedSats);
- lcd.setCursor(0, 0); lcd.print(sBuffer0);
- }
- }
- void WiFi_Init() {
- #if defined AP_MODE
- #define HOSTNAME "GNSS_Nmea"
- #define SSID_NAME HOSTNAME
- #define PASSWORD "12345678" // Mini. 8 car
- // bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dhcp_lease_start = (uint32_t) 0);
- // bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4, bool ftm_responder = false);
- WiFi.softAPConfig(localIP, gatewayIP, subnetMaskIP, dhcp_startIP);
- WiFi.softAP(SSID_NAME, PASSWORD, 1, 0, 8, false);
- localIP = WiFi.softAPIP();
- subnetMaskIP = WiFi.softAPSubnetMask();
- broadcastIP = WiFi.softAPBroadcastIP();
- #else
- #define HOSTNAME "GNSS_Nmea"
- #define SSID_NAME "ssid_name" // to change
- #define PASSWORD "password" // to change
- DisplayIMessage("Connecting " + String(SSID_NAME), true, true );
- WiFi.setHostname(HOSTNAME);
- WiFi.begin(SSID_NAME, PASSWORD);
- while (WiFi.status() != WL_CONNECTED) {
- delay(250);
- DisplayIMessage(".", false, false);
- }
- localIP = WiFi.localIP();
- subnetMaskIP = WiFi.subnetMask();
- gatewayIP = WiFi.gatewayIP();
- broadcastIP = WiFi.broadcastIP();
- #endif
- DisplayIMessage("IP " + localIP.toString(), true, true);
- //DisplayIMessage("Mask " + subnetMask.toString(), false, true);
- //DisplayIMessage("Broad." + broadcastIP.toString(), false, true);
- // DisplayIMessage("GW " + gatewayIP.toString(), false, true);
- DisplayIMessage("Port " + String (UDP_PORT), false, true);
- }
- void Storage_Init() {
- #if defined USING_SPIFFS
- if(!SPIFFS.begin(true))
- DisplayIMessage("Storage Mount Failed", false, true);
- else {
- DisplayIMessage("Storage Mount OK", false, true);
- }
- #endif
- delay(2500);
- lcd.clear();
- }
- void Display_Init() {
- lcd.init(); // I2C LCD init command
- bLCDDisplay = true;
- lcd.backlight(); // I2C LCD turn backlight on
- lcd.setCursor(3, 0); lcd.print("GNSS NMEA0183");
- lcd.setCursor(1, 2); lcd.print("version 2024-12-03");
- lcd.setCursor(3, 3); lcd.print("by Patrick D.");
- delay(2500);
- lcd.clear();
- }
- void DisplayIMessage(String sMessage, bool bClear, bool bCRLN) {
- static int nRow = 0;
- if (bLCDDisplay) {
- if (bClear) {
- lcd.clear();
- lcd.setCursor(0, nRow=0);
- }
- if (bCRLN) {
- lcd.setCursor(0, nRow++);
- lcd.print(sMessage);
- }
- else
- lcd.print(sMessage);
- }
- else
- Serial.println(sMessage);
- }
- String DD_to_DMS(float fValue) {
- static int deg, arcMinutes;
- static float minutesRemainder, arcSeconds;
- static char buffer[16];
- fValue = abs(fValue);
- deg = fValue;
- minutesRemainder = abs(fValue - deg) * 60;
- arcMinutes = minutesRemainder;
- arcSeconds = (minutesRemainder - arcMinutes) * 60;
- sprintf(buffer," %03d%c%02d'%05.2f\"", deg, byte(223), arcMinutes, arcSeconds);
- return String(buffer);
- }
- String * DecimalDegrees_to_DegreesMinutesSeconds(float fLat, float fLng) {
- /* Latitude +N 0-90
- Latitude -S
- Longitude +E 0-180
- Longitude -W */
- static String sLat, sLng;
- static String sDMS[2]; // array of String to return
- // fLat = -fLat ; fLng = -fLng; // to test South and West :-)
- sLat = DD_to_DMS(fLat);
- sLat.concat(fLat < 0 ? "S" : "N");
- sDMS[LAT] = sLat;
- sLng = DD_to_DMS(fLng);
- sLng.concat(fLng < 0 ? "W" : "E");
- sDMS[LNG] = sLng;
- return sDMS;
- }
- void OTA_Init(){
- // ArduinoOTA.setPort(3232); // Port defaults
- ArduinoOTA.setHostname(HOSTNAME); // Hostname defaults to esp3232-[MAC]
- ArduinoOTA.setPassword(PASSWORD); // No authentication by default
- // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // Password can be set with it's md5 value as well
- // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");
- ArduinoOTA
- .onStart([]() {
- String type;
- if (ArduinoOTA.getCommand() == U_FLASH)
- type = "sketch";
- else // U_SPIFFS
- type = "filesystem";
- // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
- Serial.println("Start updating " + type);
- })
- .onEnd([]() {
- Serial.println("\nEnd");
- })
- .onProgress([](unsigned int progress, unsigned int total) {
- Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
- })
- .onError([](ota_error_t error) {
- Serial.printf("Error[%u]: ", error);
- if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
- else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
- else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
- else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
- else if (error == OTA_END_ERROR) Serial.println("End Failed");
- });
- ArduinoOTA.begin();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement