ESP32 ottimizzazione del modulo Neo-6M GPS

A cosa può servire un modulo GPS su ESP32?
Io ho comprato il NEO-6M (vero o falso cmq funziona) con antenna attiva sul sito:
https://it.aliexpress.com/item/1005004841512460.html?spm=a2g0o.order_list.order_list_main.23.ed733696n9BE98&gatewayAdapt=glo2ita
(7€ con la spedizione)
per avere un aggiornamento di data e ora sulla macchina senza avere una connessione wifi o schede con orologio interno che in genere richiedono poi un'aggiornamento (sempre wifi) perchè col passare delle ore/giorni tendono a scostarsi dall'ora precisa e che cmq devono avere una batteria di alimentazione costante per funzionare.
Il mio ESP32 prende l'alimentazione dall'accendisigari della macchina, per cui quando tolgo la chiave della macchina non assorbe corrente.
Consiglio a questo punto, se volete utilizzarlo(e se avete un modulo GPS con chip Ublox), di installare il programma U-CENTER dal sito ufficiale:

perchè con questo programma potete modificare parecchi parametri del GPS e salvarli nella sua memoria interna
e installare anche il programma Google Earth se non lo avete ancora :

per vedere la posizione del GPS sulla mappa 3D che vengono trasmesse automaticamente dal programma U-Center nel primo menù Database export/Google Earth server

COLLGAMENTI PC-GPS
Per collegarmi al modulo GPS (piazzato in balcone con case di fronte per cui non nella posizione ottimale che sarebbe in campo aperto senza neanche alberi o nuvole) dal PC ho utilizzato una prolunga di 5 metri USB e un modulo USB-TTL
L'uscita TX del modulo TTL và collegata alla porta RX del modulo GPS e RX del modulo TTL alla TX del modulo GPS.
RICORDO CHE IL MODULO NEO-6M VÀ ALIMENTATO A 3.3 VOLT
PER CUI PRENDETE L'ALIMENTAZIONE DALL'USCITA 3.3V DEL MODULO TTL o da ESP32
Se non avete un modulo USB-TTL potete utlizzare anche ESP32 con una routine simile a questa:

// In questo esempio sto utilizzando un ESP32-2432S028 Yellow in cui i pin di default (16 e 17) per la Uart 2 sono stati
// utilizzati per il led posteriore...a cosa serve?...un pò di fuochi d'artificio?...visto che non è neanche sul frontale ma sul retro
//Per cui sto utilizzando i pin 21 e 22 disponibili su una porta di espansione + GND e prendo i 3.3 Volt dalla porta accanto
// ma se state usando un ESP32 tradizionale potete usare i pin 16 e 17
#include <HardwareSerial.h>
#define RX 21          // Connesso al modulo GPS TX pin   per ESP32 normale è il pin 16
#define TX 22          // Connesso al modulo GPS RX pin   per ESP32 normale è il pin 17
HardwareSerial GPS(1);  // Usiamo UART1  mentre UART0/Seriale è usato per ricevere/inviare i messaggi da USB
void setup() {
  Serial.begin(9600);
  delay(500);
  while (Serial.available() > 0) {// elimino buffer
    Serial.read();
  }
  GPS.begin(9600, SERIAL_8N1, RX, TX);  // Serial GPS
  delay(500);
  while (GPS.available() > 0) {
    GPS.read();
  }
 }
void loop() {
  int len = GPS.available();
  while (len > 0) {  // Do blocks of bytes for efficiency
    uint8_t buffer[128];
    int xferlen = len;
    if (len > sizeof(buffer)) xferlen = sizeof(buffer);
    GPS.readBytes(buffer, xferlen);
    Serial.write(buffer, xferlen);
    len -= xferlen;
  }
  int len2 = Serial.available();
  while (len2 > 0) {  // Do blocks of bytes for efficiency
    uint8_t buffer2[128];
    int xferlen2 = len2;
    if (len2 > sizeof(buffer2)) xferlen2 = sizeof(buffer2);
    Serial.readBytes(buffer2, xferlen2);
    GPS.write(buffer2, xferlen2);
    len2 -= xferlen2;
  }
}

Con questo sketch di base possiamo aprire Ucenter e visualizzare o modificare le impostazioni del nostro modulo GPS-
Per cui andiamo nel menù View/Messages (F9) e scorrendo in basso nella finestra apriamo UBX che presenta tutta una serie di parametri modificabili e ci visualizza il comando in esadecimale che possiamo utilizzare poi nel nostro sketch per modificare il dato parametro.
Ad esempio in UBX/CFG/RATE UTC Time 500 ms 2Hz (max per Neo-6M è 5Hz) possiamo impostare un rateo di aggiornamento più veloce nell'aggiornare i dati provenienti dal modulo GPS (che di default è 1000 ms) e questo permette una maggiore risoluzione e quindi cambiamenti più discreti tra una lettura e la successiva.
Questo di 500ms è il limite massimo che il programma Ucenter supporta per un aggiornamento delle varie finestre, perchè se impostate un rateo maggiore (max per Neo-6M è 5Hz) le finestre del programma non riescono più ad aggiornarsi, ma se invece leggete i dati sul serial monitor di arduino (spegnendo Ucenter) io ho provato sino a 5Hz e arrivano tranquillamente anche con la seriale impostata a 9600 Baud.

Ora vediamo quali messaggi NMEA escludere dalla trasmissione tra il GPS e ESP32
Un elenco di messaggi lo trovate all'indirizzo:
https://aprs.gids.nl/nmea/#gga
Come potete vedere parecchi dati contenuti nei messaggi si ripetono anche in altri messaggi, per cui è inutile riempire la seriale di messaggi che non ci servono perchè i dati sono contenuti già in altri messaggi.
In particolare a me interessava la data e l'ora per cui ho escluso gli altri messaggi e selezionato solo F0-00 NMEA GxGGA e F0-04 NMEA GxRMC (e in essi sono contenute anche la latitudine/longitudine/altezza, numero di satelliti, validità dei dati ricevuti)
Però se volete continuare a vedere i risultati in Ucenter NON dovete disabilitare UBX/CFG/MSG (Messages GPS Satellites in view) F0-03 NMEA GxGSV perchè lo usa nella visualizzazione delle finestre.
Altri mesaggi possono risultare utili per muoversi da un waipoint ad un altro, indicandovi la direzione e la velocità di spostamento, dipende dalla vostra applicazione di quali dati avete bisogno.

COME MIGLIORARE LA QUALITÀ DEL SEGNALE
Come riportato da Wiki: "Satellite-based augmentation system - SBAS Questi sistemi supportano vaste regioni anche su scala continentale, attraverso l'utilizzo di satelliti geo-stazionari, equipaggiati con apparati in grado di trasmettere segnali simili a quelli emessi da un satellite GNSS, che diffondono l'informazione incrementata. Uno SBAS accresce la costellazione primaria di GNSS fornendo l'allineamento dei satelliti geo-stazionari, l'integrità del segnale e l'informazione di correzione. Sebbene lo scopo principale dello SBAS sia quello di assicurare l'integrità del segnale, questo in effetti ne aumenta anche l'accuratezza con errori di posizione inferiori al metro."
E' già attivato nella configurazione di default, però và attivato anche in UBX/CFG/GNSS (Config) GPS+SBAS Configure+Enable per dire al GPS di considerare anche i messaggi SBAS e settare Auto set nel umero di canali.
Questa è stata la configurazione che mi ha dato minori spostamenti in velocità (sotto lo zero) e in altezza (+- 5 metri).
Ma ripeto, la posizione dell'antenna sul balcone con case di fronte non è nelle condizioni ottimali (che sono in campo aperto, niente alberi, nessuna nuvola).
C'è poi il sistema RTK, ovvero (Real Time Kinematic). è una tecnica GNSS differenziale che fornisce elevate prestazioni di posizionamento nelle vicinanze di una stazione base. La tecnica si basa sull'uso di misurazioni portanti e sulla trasmissione di correzioni dalla stazione base, la cui posizione è ben nota, al rover, in modo che gli errori principali che guidano il posizionamento autonomo si annullino.
L‟utilizzo di questa tecnica di misura è però limitato dagli effetti generati da ionosfera e troposfera sul segnale che le attraversa.
Possiamo selezionare la voce nel menù UBX/CFG/DGNSS e selezionare l'opzione Differential mode 3 che la utilizza se c'è un segnale disponibile.

C'è poi un filtro anti-jamming sull'antenna che si può selezionare e modificare alla voce UBX/CFG/ITFM

Esistono poi altri filtri tipo il Extended Kalman Filter (EKF) che però funzionano in abbinamento a dati provenienti da giroscopio e odometro utili per la navigazione e bussola.

CONFIGURAZIONE
E quà veniamo alla parte dolente, perchè in teoria il mio modulo ha una batteria tampone per cui la configurazione dovrebbe venire salvata in memoria ma purtroppo allo spegnimento del modulo si perdono tutti i settaggi e si torna alla configurazione di default, per cui con ESP32 nel Setup dobbiamo reinviare i comandi che ci interessano (e non sono pochi) con tanto di checksum alla fine.
Per creare questi comandi ci viene in aiuto Ucenter perchè abilitando la finestra esadecimale avremo la stringa con il checksum già calcolato ad esempio B5 62 06 39 08 00 F3 AC 62 AD 1E 63 00 00 76 A5 e con Notepad++ possiamo fare una sostituzione degli spazi con la stringa ", 0x" per ottenere una stringa 0xB5, 0x62, 0x06, 0x39, 0x08, 0x00, 0xF3, 0xAC, 0x62, 0xAD, 0x1E, 0x63, 0x00, 0x00, 0x76, 0xA5 che verrà messa in un array ed inviata al modulo GPS con il comando GPS.write(byteread); (ovvero in esadecimale)
Un esempio di come inviarli lo riporto quà sotto:

// nella dichiarazione delle variabili mettere:
#include <HardwareSerial.h>
#define RX 21          // Connesso al modulo GPS TX pin   per ESP32 normale è il pin 16
#define TX 22          // Connesso al modulo GPS RX pin   per ESP32 normale è il pin 17
HardwareSerial GPS(1);  // Usiamo UART1  mentre UART0/Seriale è usato per ricevere/inviare i messaggi da USB
const PROGMEM uint8_t GpsRate[] = { 0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xF4, 0x01, 0x01, 0x00, 0x01, 0x00, 0x0B, 0x77 };  // 500ms rispetto ai 1000ms di default
// in SETUP dopo aver aperto le 2 seriali mettere:
GPS_SendConfig(GpsRate, 14);  //500 ms Dove GpsRate è l'array e 14 è il numero di dati presente nell'array

// fine Setup
// e poi utilizzare questa subroutine:
void GPS_SendConfig(const uint8_t *Progmem_ptr, uint8_t arraysize) {
  uint8_t byteread, index;
  Serial.print(F("GPSSend  "));
  for (index = 0; index < arraysize; index++) {
    byteread = pgm_read_byte_near(Progmem_ptr++);
    if (byteread < 0x10) {
      Serial.print(F("0"));
    }
    Serial.print(byteread, HEX);
    Serial.print(F(" "));
  }
  Serial.println();
  Progmem_ptr = Progmem_ptr - arraysize;  //set Progmem_ptr back to start
  for (index = 0; index < arraysize; index++) {
    byteread = pgm_read_byte_near(Progmem_ptr++);
    GPS.write(byteread);
  }
  delay(100);
}

***************** COMANDI *************
FACCIO PRESENTE che questi comandi sono stati ottenuti settando UART1 come porta di collegamento col modulo GPS, se voi utilizzate un'altra porta vanno ricalcolati con il programma Ucenter.

Ora metto una serie di comandi che ho utilizzato in parte, stà a voi quale intendete utilizzare:

UBX/CFG/CFG (Configuration) Revert to default configuration
21 Data
0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1B, 0x9A

UBX/CFG/CFG (Configuration) Revert to last saved configuration SUL MIO MODULO GPS NON FUNZIONA
21 Data
0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1D, 0xB3

UBX/CFG/CFG (Configuration) Save current configuration
21 Data
0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1D, 0xAB

UBX/CFG/RST Forced Reset (watchdog) User Defined (all)
12 Data
0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B

***************************** GNSS ************************************
UBX/CFG/GNSS (config) GPS(10) + Galileo (10) + Glonass (10)
36 Data
0xB5, 0x62, 0x06, 0x3E, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x01, 0x01, 0x02, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x01, 0x01, 0x06, 0x01, 0x0A, 0x00, 0x01, 0x00, 0x01, 0x01, 0x95, 0x53

UBX/CFG/GNSS (Config) GPS+SBAS Configure+Enable + Auto Set channels --- USARE QUESTA PER SBAS
28 Data
0xB5, 0x62, 0x06, 0x3E, 0x14, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x5F, 0x1E


UBX/CFG/SBAS gli SBAS correggono gli effetti dei ritardi atmosferici sui segnali trasmessi dai satelliti
Ranging(use SBAS in NAV) Apply SBAS correction data Apply integrity information Channel 3 Auto-scan
16 Data
0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x01, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xD5

UBX/CFG/GEOFENCE (config) Confidence level 0 (no confidence required)
16 Data
0xB5, 0x62, 0x06, 0x69, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x1B

****************************** RATE **********************************
UBX/CFG/RATE UTC Time 500 ms 2Hz (max per Neo-6M è 5Hz)
14 Data
0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xF4, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x75

UBX/CFG/RATE UTC Time 200 ms 5Hz (max per Neo-6M è 5Hz)
14 Data
0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xC8, 0x00, 0x01, 0x00, 0x00, 0x00, 0xDD, 0x68


UBX/CFG/ITFM (Jamming/interferences of antenna) Broadband 3dB CW 15dB Antenna type Active Enable Jamming monitor
16 Data
0xB5, 0x62, 0x06, 0x39, 0x08, 0x00, 0xF3, 0xAC, 0x62, 0xAD, 0x1E, 0x63, 0x00, 0x00, 0x76, 0xA5

+++++++++++++++++++++++++++ MESSAGGI OFF +++++++++++++++++++++++
UBX/CFG/MSG (Messages Global Positioning System Fix Data) F0-00 NMEA GxGGA all off ---------------- NO
16 Data
0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x24

UBX/CFG/MSG (Messages Global Positioning System Fix Data) F0-00 NMEA GxGGA ON UART 1
16 Data
0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x29

UBX/CFG/MSG (Messages Geographic Position, Latitude / Longitude and time.) F0-01 NMEA GxLL all off
16 Data
0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x2B

UBX/CFG/MSG (Messages GPS DOP and active satellites ) F0-02 NMEA GxGSA all off
16 Data
0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x32

UBX/CFG/MSG (Messages GPS Satellites in view) F0-03 NMEA GxGSV all off ------- NO per Ucenter
16 Data
0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x39

UBX/CFG/MSG (Messages Recommended minimum specific GPS/Transit data) F0-04 NMEA GxRMC all off -------------- NO
16 Data
0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x40

UBX/CFG/MSG (Messages Recommended minimum specific GPS/Transit data) F0-04 NMEA GxRMC ON Uart 1
16 Data
0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x45

UBX/CFG/MSG (Messages Track Made Good and Ground Speed.) F0-05 NMEA GxVTG all off
16 Data
0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x47
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

La velocità di trasmissione del modulo Neo-6M è settata a 9600 Baud e questo viene resettato quando si toglie l'alimentazione, ma se vogliamo possiamo anche settarla a 115200 Baud, ma solo dopo aver aperto la porta UART1 a 9600 Baud, altrimenti il comando non verrà riconosciuto.

UBX/CFG/PRT ( Ports ) Target UART1 Protocol IN UBX+NMEA Protocol OUT UBX+NMEA Baudrate 115200
28 Data
0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x5E

inserendo questi comandi :

// nella dichiarazione delle variabili mettiamo questo array
const PROGMEM uint8_t GpsBaud[] = { 0xB5, 0x62, 0x06, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x08, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x5E};
#define RX 21          // Connesso al modulo GPS TX pin   per ESP32 normale è il pin 16
#define TX 22          // Connesso al modulo GPS RX pin   per ESP32 normale è il pin 17

//in SETUP mettiamo:
Serial.begin(115200);
  delay(500);
  while (Serial.available() > 0) {// elimino buffer
    Serial.read();
  }
GPS.begin (9600, SERIAL_8N1, RX, TX); //modalità predefinita 
 // mettere prima gli altri comandi che ci interessano a 9600 Baud e alla fine cambiamo la velocità della porta
  GPS_SendConfig(GpsBaud, 28); // prima viene cambiata la velocità nel modulo GPS e poi nella UART1
  GPS.begin (115200, SERIAL_8N1, RX, TX); //nuova modalità boost 115200 Baud
// fine Setup

void GPS_SendConfig(const uint8_t *Progmem_ptr, uint8_t arraysize) {
uint8_t byteread, index;
  for (index = 0; index < arraysize; index++) {
    byteread = pgm_read_byte_near(Progmem_ptr++);
    GPS.write(byteread);
  }
  delay(100);
}

Prossimamente metterò anche la routine che legge i comandi in arrivo, li mette in un'array e così possiamo prendere il dato che ci interessa all'interno del messaggio inviato dal gps, il tutto senza utilizzare librerie esterne (tipo TinyGps o simli) che occupano parecchia memoria.

Ora metto il programma che vi avevo anticipato, ovvero vengono inviati nel Setup una serie di comandi al GPS, per avere poi come risposta solo i messaggi $GPGGA e $GPRMC sulla seriale.
In questi due messaggi sono contenuti i parametri che mi interessano per settare l'orologio di ESP32 e, una volta settato, escludo anche i messaggi $GPRMC perchè mi interessavano solo per settare la data del giorno/anno, l'altro dato contenuto in questo messaggio e che non c'è in $GPGGA è la velocità di spostamento, ma, essendo destinato all'uso sulla macchina come avevo precisato all'inizio del post, risulta inutile (c'è già il contachilometri della macchina e il sistema ODBII che rilevano la velocità).
Nel messaggio $GPGGA oltre all'ora, latitudine/longitudine è interessante la rilevazione dell'altezza (che nella mia macchina non c'è) , inoltre gli collego una sonda per la rilevazione della temperatura esterna e un eventuale buzzer in caso di temperatura sotto lo zero.
Quando mi arriva la sonda e un'antenna che dovrebbe essere meglio di quella in dotazione vedrò di implementare i dati su un'interfaccia grafica per ESP 32 Yellow.
Per ora l'uscita dei dati è solo sulla seriale e ho messo un aggiornamento di 5 secondi per non rallentare la lettura dei dati in arrivo dal gps, ma se volete vedere potete impostarla a 1 secondo per vedere il cambiamento dei secondi in tempo reale.

//  NEO-6M-0-001 V2   allo start ricevo $GPTXT,01,01,02,ANTSTATUS=OK*3B
// ESP32-2432S028 16 BIT RGB65K color display
//Example:$GPGGA,202530.00,5109.0262,N,11401.8407,W,5,40,0.5,1097.36,M,-17.00,M,18,TSTR*61
//0 Sentence Identifier	$GPGGA	Global Positioning System Fix Data
//1 Time	170834	17:08:34
//2 Latitude	4124.8963, N	41d 24.8963' N or 41d 24' 54" N
//3 Latitude direction (N = North, S = South)
//4 Longitude	08151.6838, W	81d 51.6838' W or 81d 51' 41" W
//5 Longitude direction (E = East, W = West)
//6 Fix Quality:(0-9)   https://docs.novatel.com/OEM7/Content/Logs/GPGGA.htm#GPSQualityIndicators
//7 Number of Satellites	05	5 Satellites are in view
//8 Horizontal Dilution of Precision (HDOP)	1.5	Relative accuracy of horizontal position
//9 Altitude	280.2, M	280.2 meters above mean sea level
//10 Units of antenna altitude (M = metres)
//11 Undulation - the relationship between the geoid and the WGS84 ellipsoid
//12 Units of undulation (M = metres)
//13 Time since last DGPS update	blank	No last update
//14 DGPS reference station id	blank	No station id
//15 Checksum	Used by program to check for transmission errors

//                  1 ORA       3 LAT       5 LONG    7 SPEED  9 DATA
// $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
//  225446       Time of fix 22:54:46 UTC
//  A            Navigation receiver warning A = OK, V = warning
//  4916.45,N    Latitude 49 deg. 16.45 min North
//  12311.12,W   Longitude 123 deg. 11.12 min West
//  000.5        Speed over ground, Knots
//  054.7        Course Made Good, True
//  191194       Date of fix  19 November 1994
//  020.3,E      Magnetic variation 20.3 deg East
//  *68          mandatory checksum


#include <Arduino.h>
#include <HardwareSerial.h>
#include <TimeLib.h>  // https://github.com/PaulStoffregen/Time

const PROGMEM uint8_t DefaultConfig[] = { 0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1B, 0x9A };

// UBX/CFG/RST Forced Reset (watchdog)  User Defined (all)   12 Data
//const PROGMEM uint8_t RST[] = { 0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B };
const PROGMEM uint8_t GNSS[] = { 0xB5, 0x62, 0x06, 0x3E, 0x14, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x5F, 0x1E };
const PROGMEM uint8_t SBAS[] = { 0xB5, 0x62, 0x06, 0x16, 0x08, 0x00, 0x01, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xD5 };
const PROGMEM uint8_t RTK[] = { 0xB5, 0x62, 0x06, 0x70, 0x04, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7D, 0x64 };
const PROGMEM uint8_t JAM[] = { 0xB5, 0x62, 0x06, 0x39, 0x08, 0x00, 0xF3, 0xAC, 0x62, 0xAD, 0x1E, 0x63, 0x00, 0x00, 0x76, 0xA5 };
const PROGMEM uint8_t GLL_Off[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x2B };
const PROGMEM uint8_t GSA_Off[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x32 };
const PROGMEM uint8_t GSV_Off[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x39 };
const PROGMEM uint8_t VTG_Off[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x47 };
const PROGMEM uint8_t RMC_Off[] = { 0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x40 };
const PROGMEM uint8_t GpsRate[] = { 0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xFA, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x96 };  // 250 MS ---
//const PROGMEM uint8_t GpsRate[] = { 0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xF4, 0x01, 0x01, 0x00, 0x01, 0x00, 0x0B, 0x77 };  // 500Ms
//const PROGMEM  uint8_t GpsRate[] = {0xB5, 0x62, 0x06, 0x08, 0x06, 0x00, 0xE8, 0x03, 0x01, 0x00, 0x01, 0x00, 0x01, 0x39};// 1000 MS ---

HardwareSerial GPS(1);  // Use UART1

String RxBuffer, T;
static String GiornoSett[] = { "Domenica", "Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato" };
char RxByte;
unsigned long TimerGPS, AggiornoOrologio;
String Diviso[17];
char TT[128];
int conto, t1, t2, DatiValidi = 0, OrologioSettato, Altezza, Qualita, Satelliti;
float Long, Lat;
const int offset = 2;  // Central European Time=1 ma mettere a 2 per ora legale

void setup() {
  Serial.begin(115200);
  delay(500);
  while (Serial.available() > 0) {
    Serial.read();
  }
  // GPS.begin(9600, SERIAL_8N1, 21, 22);  // Serial GPS YELLOW
  GPS.begin(9600, SERIAL_8N1, 16, 17);  // Serial UART1 ESP32 classic
  delay(500);
  while (GPS.available() > 0) {
    GPS.read();
  }
  GPS_SendConfig(DefaultConfig, 21);  //UBX/CFG/CFG (Configuration) Revert to default configuration
  delay(2000);
  GPS_SendConfig(GNSS, 28);     //UBX/CFG/GNSS (Config) GPS+SBAS Configure+Enable + Auto Set channels
  GPS_SendConfig(SBAS, 16);     //UBX/CFG/SBAS gli SBAS correggono gli effetti dei ritardi atmosferici sui segnali trasmessi dai satelliti
  GPS_SendConfig(RTK, 12);      // modo 3=RTK fixed ambiguities whenever possible
  GPS_SendConfig(JAM, 16);      //UBX/CFG/ITFM (Jamming/interferences of antenna) Broadband 3dB   CW 15dB   Antenna type Active
  GPS_SendConfig(GLL_Off, 16);  //F0-01 MESSAGGI ESCLUSI
  GPS_SendConfig(GSA_Off, 16);  //F0-02
  GPS_SendConfig(GSV_Off, 16);  //F0-03
  GPS_SendConfig(VTG_Off, 16);  //F0-05
  GPS_SendConfig(GpsRate, 14);  //250 Ms
  while (GPS.available() > 0) {
    GPS.read();
  }
  GPS.flush();
  TimerGPS = millis() + 250;
  AggiornoOrologio = millis() + 5000;
}

void loop() {
  if (millis() >= AggiornoOrologio && OrologioSettato == 1) {
    SettoOra();
  }
  if (DatiValidi == 0 || millis() >= TimerGPS) {
    LeggoGPS();
  }
}
void LeggoGPS() {
  while (GPS.available() > 0) {
    RxBuffer = GPS.readStringUntil('\n');    
    if (RxBuffer.startsWith("$")) {              // controllo se la stringa comincia con $
      t1 = RxBuffer.indexOf("*");                // cerco il cecksum
      RxBuffer = RxBuffer.substring(0, t1 + 3);  // elimino eventuali dati dopo il cecksum
      if (RxBuffer.startsWith("$GPGGA")) {  // ******************* GPGGA *********************************
        Spli(16);
        Lat = Diviso[2].toFloat();
        Long = Diviso[4].toFloat();
        Qualita = Diviso[6].toInt();
        Satelliti = Diviso[7].toInt();
        Altezza = Diviso[9].toInt();
        if (Qualita > 0 && Satelliti > 0) {
          DatiValidi = 1;
        } else {
          Serial.println("Dati non validi");
          DatiValidi = 0;
        }
        RxBuffer = "";
      }
      if (RxBuffer.startsWith("$GPRMC")) {  // **************** GPRMC  *************************
        Spli(12);
        if (DatiValidi == 1) {
          if (OrologioSettato == 0) {
            setTime(((Diviso[1].substring(0, 2)).toInt()), ((Diviso[1].substring(2, 4)).toInt()), ((Diviso[1].substring(4, 6)).toInt()), ((Diviso[9].substring(0, 2)).toInt()), ((Diviso[9].substring(2, 4)).toInt()), ((Diviso[9].substring(4, 6)).toInt()));  //setTime(Hour, Minute, Second, Day, Month, Year);
            adjustTime(offset * SECS_PER_HOUR);       // offset er fuso orario/ora legale
            OrologioSettato = 1;
            GPS_SendConfig(RMC_Off, 16);  //F0-04 // escludo i comandi RMC dopo chee l'orologio è stato settato
            TimerGPS = millis() + 250;
          }
        }
      }
      RxBuffer = "";
    } else {  // se la stringa non comincia con $ cancello il buffer
      RxBuffer = "";
    }
  }
}
void Spli(uint8_t max) {
  for (int i = 0; i < 17; i++) {
    Diviso[i] = "";
  }
  String CAR = "";
  conto = 0;
  t1 = 0;
  t2 = 0;
  T = RxBuffer;
  t1 = T.indexOf(",");  // prima virgola inizio Ora/Minuti/Secondi
  Diviso[conto] = T.substring(0, t1);
  conto++;
  do {
    t2 = T.indexOf(",", t1 + 1);  // seconda virgola
    if (t1 + 1 != t2) {           // se ci sono 2 virgole vicine il campo è vuoto
      CAR = T.substring(t1 + 1, t2);
      if (conto == 1) {  // controllo se l'ora è di lunghezza corretta 
        if (CAR.length() != 9) {
          Serial.print("messaggio non valido  ");
          Serial.println((String)CAR.length());
          break;
        }
      }
    } else {
      CAR = "***";
    }
    Diviso[conto] = CAR;
    conto++;
    t1 = t2;
  } while (conto < max);
  //return 0;
}
void GPS_SendConfig(const uint8_t *Progmem_ptr, uint8_t arraysize) {
  uint8_t byteread, index;
  for (index = 0; index < arraysize; index++) {
    byteread = pgm_read_byte_near(Progmem_ptr++);
    GPS.write(byteread);
  }
  delay(100);
}

void SettoOra() {
  time_t t = now();
  Serial.println("");
  //Serial.println("***********************");
  Serial.print(GiornoSett[weekday(t) - 1]);
  Serial.print(" ");
  Serial.print(hour(t));
  Serial.print(":");
  Serial.print(minute(t));
  Serial.print(":");
  Serial.print(second(t));
  Serial.print("   ");
  Serial.print(day(t));
  Serial.print("/");
  Serial.print(month(t));
  Serial.print("/");
  Serial.print(year(t));
  Serial.print("    Altezza = ");
  Serial.println(Altezza);
  //Serial.println("***********************");
  Serial.println();
  AggiornoOrologio = millis() + 5000;
  //return 0;
}

Aggiungo uno screenshot di come procede l'interfaccia grafica, con bottoni per cambiare la luminosità dello schermo e il fuso orario (che vengono salvati su SPIFFS nelle preferenze)

1 Like

Bravo

E grazie per la condivisione

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.