Bonjour,
Suite au projet que j'ai mis en ligne GPS avec fichier GPX et avec lequel je ne rencontre pas de problème (je cours 3 à 4 fois par semaine). Je tiens quand même compte des remarques de JML pour lequel j'ai beaucoup de respect :
Il a raison nos petits µcontrôleurs sont limités en mémoire et la classe String a de sérieux inconvénients. Du coup, je travaille sur le même projet mais cette fois-ci avec les c-string.
Je me suis inspiré de son code ici : https://forum.arduino.cc/t/ecouter-le-port-serie-ou-un-keypad-applicable-a-1-flux-de-donnees-asynchrone/480990/5
Voici le code brut que j'ai écrit rapidement et qui me permet d'extraire n'importe quelle donnée des phrases NMEA de mon GPS.
char latitu [18], longitu[18];
char alti[18], sate[18], hdopss[18];
char dateHeure[25];
char *variablesGpx[83];// = {"phraseNmea","heure","latit","longit","Date","alt","sat","hdops",'\0'};
int typePhrase;
const byte tailleMessageMax = 82;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'
const char marqueurDeFin = '\n';
boolean reception = false;
//Déclaration procédure et fonctions
//char *extraction(*mess);
void setup() {
Serial.begin(9600);
Serial1.begin(9600, SERIAL_8N1, 16, 17); // initialise la liaison RX2-TX2 sur expressif WROOM 32
}
void loop() {
ecouteGps();
if (reception) {
Serial.print("latitude :" ); Serial.println(latitu);
Serial.print("longitude :" ); Serial.println(longitu);
Serial.print("altitude :"); Serial.println(alti);
Serial.print("Nb satellites :"); Serial.println (sate);
Serial.print ("hdop :"); Serial.println (hdopss);
Serial.println(dateHeure);
}
}
void ecouteGps() {
if (!ecouter()) {
// on a reçu le marqueur de fin
if (strstr(message, "$GPRMC")) {
traitement(message, 1);
}
if (strstr(message, "$GPGGA")) {
traitement(message, 2);
}
if (strstr(message, "$GPGSA")) {
traitement(message, 3);
}
}
}
boolean ecouter()
{
static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
boolean messageEnCours = true;
while (Serial1.available() && messageEnCours) {
int c = Serial1.read();
if (c != -1) {
switch (c) {
case marqueurDeFin:
message[indexMessage] = '\0'; // on termine la c-string
indexMessage = 0; // on se remet au début pour la prochaine fois
messageEnCours = false;
break;
default:
if (indexMessage <= tailleMessageMax - 1) message[indexMessage++] = (char) c; // on stocke le caractère et on passe à la case suivante
break;
}
}
}
return messageEnCours;
}
//=======================================Extraction des variables GPX
void traitement(char *message, int types) {
char *heures, *dates;
char *latit, *longit;
char *alt, *sat, *hdops;
// Extraction des phrases
int nbVirgule = 0;
char *champNmea = NULL;
champNmea = strtok (message, ",");
while (champNmea != NULL)
{
champNmea = strtok (NULL, ",");
variablesGpx[nbVirgule] = champNmea;
nbVirgule++;
}
variablesGpx[nbVirgule] = '\0';
// Extraction des phrases
if (types == 1) { //GPRMC
heures = variablesGpx[0];
latit = variablesGpx[2];
longit = variablesGpx[4];
dates = variablesGpx[7];
conversionDecimal(latit, 1);
conversionDecimal(longit, 0);
timeGpx(dates, heures);
}
if (types == 2) { //GPGGA
sat = variablesGpx[6];
alt = variablesGpx[8];
sprintf(alti, "%s", alt);
sprintf(sate, "%s", sat);
}
if (types == 3) { //GPGSA
hdops = variablesGpx[nbVirgule - 3];
sprintf(hdopss, "%s", hdops);
}
}
//=======================================Formate la date et l'heure au format GPX
char timeGpx(char *lesDates, char *lesHeures ) {
char annee[3], mois[3], jour[3], heure[3], minut[3], secon[3];
jour[0] = lesDates[0];
jour[1] = lesDates[1];
jour[2] = '\0';
mois[0] = lesDates[2];
mois[1] = lesDates[3];
mois[2] = '\0';
annee[0] = lesDates[4];
annee[1] = lesDates[5];
annee[2] = '\0';
heure[0] = lesHeures[0];
heure[1] = lesHeures[1];
heure[2] = '\0';
minut[0] = lesHeures[2];
minut[1] = lesHeures[3];
minut[2] = '\0';
secon[0] = lesHeures[4];
secon[1] = lesHeures[5];
secon[2] = '\0';
sprintf(dateHeure, "20%2s-%2s-%2sT%02s:%02s:%02sZ", annee, mois, jour, heure, minut, secon);
}
//=======================================Retoune la latitude ou la longitude en degres decimal
char* conversionDecimal (char *latlong, boolean lati) {
//char x[30];
char degres[4];
char minut [10];
if (lati) {
degres[0] = latlong[0];
degres[1] = latlong[1];
degres[2] = '\0';
minut[0] = latlong[2];
minut[1] = latlong[3];
minut[2] = latlong[4];
minut[3] = latlong[5];
minut[4] = latlong[6];
minut[5] = latlong[7];
minut[6] = latlong[8];
minut[7] = latlong[9];
minut[8] = '\0';
}
else
{
degres[0] = latlong[0];
degres[1] = latlong[1];
degres[2] = latlong[2];
degres[3] = '\0';
minut[0] = latlong[3];
minut[1] = latlong[4];
minut[2] = latlong[5];
minut[3] = latlong[6];
minut[4] = latlong[7];
minut[5] = latlong[8];
minut[6] = latlong[9];
minut[7] = latlong[10];
minut[9] = '\0';
}
double resultat = ((atoi(degres)) + ((atof(minut) / 60)));
resultat > 0 ? reception = true : reception = false;
return lati > 0 ? dtostrf(resultat, 0, NombreChiffreAVir(resultat), latitu) : dtostrf(resultat, 0, NombreChiffreAVir(resultat), longitu);
}
//=======================================supprime les '0' après la virigule lors de la conversion de la latitude ou de la longitude en degres decimal, retourne le nombre de chiffres après la virgule
int NombreChiffreAVir (double ChiffreDec) { // retourne le nombre de chiffres après la vrigule d'un nombre décimal - précision sur 13 chiffres
int nb = 0;
char tmpBuffer[21];
char *recherchePoint = strchr(dtostrf(ChiffreDec, 0, 13, tmpBuffer), '.');
if (recherchePoint == nullptr) return 0;
for (int f = strlen(tmpBuffer) - 1; f >= 0; --f)
if (tmpBuffer[f] == '0') nb++;
else break;
return 13 - nb;
}
Par contre avant que le GPS ne soit opérationnel, j'ai ce message d'erreur :
Rebooting...
'!⸮⸮⸮⸮.⸮N⸮hԀ⸮⸮Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400d0de9 PS : 0x00060730 A0 : 0x800d0f63 A1 : 0x3ffb1f00
A2 : 0x00000000 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x3ffc034c
A6 : 0x00000020 A7 : 0x3ffb0060 A8 : 0x800d0eff A9 : 0x3ffb1ec0
A10 : 0x3ffc004d A11 : 0x3ffc005d A12 : 0x00000001 A13 : 0x0000000d
A14 : 0x0000002e A15 : 0x00000030 SAR : 0x00000015 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000 LBEG : 0x400029ac LEND : 0x400029cb LCOUNT : 0x00000000
ELF file SHA256: 0000000000000000
Backtrace: 0x400d0de9:0x3ffb1f00 0x400d0f60:0x3ffb1f50 0x400d1036:0x3ffb1f70 0x400d106b:0x3ffb1f90 0x400d2395:0x3ffb1fb0 0x400860ed:0x3ffb1fd0
Il se répète jusqu'à ce que le GPS soit OK, auquel cas tout se passe normalement et les données recherchées s'affichent dans le moniteur série :
if (reception) {
Serial.print("latitude :" ); Serial.println(latitu);
Serial.print("longitude :" ); Serial.println(longitu);
Serial.print("altitude :"); Serial.println(alti);
Serial.print("Nb satellites :"); Serial.println (sate);
Serial.print ("hdop :"); Serial.println (hdopss);
Serial.println(dateHeure);
}
Voilà avant d'intégrer les fonctions qui me permettront de créer un fichier GPX, je vous soumets mon code pour savoir si je suis sur la bonne voie.
Ma configuration matériel est la même que dans mon premier projet à base de String (ESP32 - WROOM 32 - copie chinoise je pense…) .
Bonne journée.