GPS avec fichier GPX - version c-string

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.

prenons les choses dans l'ordre en nous assurant que la réception se fait comme il faut

Pouvez vous tester ce code et voir ce qu'il affiche:

const byte RXD2 = 16;
const byte TXD2 = 17;

const byte tailleMessageMax = 100;
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';

void traiterMessage() {
  Serial.print("J'ai reçu: [");
  Serial.print(message);
  Serial.println(']');

  if (strncmp(message, "$GPRMC", 6) == 0) {
    Serial.println("Trame de type RMC");
  }
  else if (strncmp(message, "$GPGGA", 6) == 0) {
    Serial.println("Trame de type GGA");
  }
  else if (strncmp(message, "$GPGSA", 6) == 0) {
    Serial.println("Trame de type GSA");
  }
  else {
    Serial.println("Trame de type inconnu");
  }
}

bool messageRecu() {
  static byte indexMessage = 0;
  int r = Serial2.read();
  if (r != -1) { // on a reçu un caractère
    if (r == marqueurDeFin) {
      message[indexMessage] = '\0'; // on termine la c-string
      indexMessage = 0; // on se remet au début pour la prochaine fois
      return true;
    } else {
      if (indexMessage < tailleMessageMax) message[indexMessage++] = (char) r; // on stocke le caractère et on passe à la case suivante
    }
  }
  return false;
}

void setup() {
  Serial.begin(115200); Serial.println();
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2); // initialise la liaison RX1-TX1 sur espressif WROOM 32
  delay(100);
}

void loop() {
  if (messageRecu()) traiterMessage();
}

il ne devrait pas y avoir de plantage de l'ESP et les trames reçues devraient être affichées sur la console série de l'ESP32 à 115200 bauds

avez vous bien une adaptation à 3.3V pour Serial2 en provenance de votre GPS (s'il parle en 5V)

Bonjour JML,
Merci pour votre aide.

J'ai reçu: [$GPRMC,134443.00,V,,,,,,,070422,,,N*7B]
Trame de type RMC
J'ai reçu: [$GPVTG,,,,,,,,,N*30]
Trame de type inconnu
J'ai reçu: [$GPGGA,134443.00,,,,,0,00,99.99,,,,,,*63]
Trame de type GGA
J'ai reçu: [$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30]
Trame de type GSA
J'ai reçu: [$GPGSV,2,1,07,16,41,302,,18,67,121,25,20,05,028,,26,76,292,29*79]
Trame de type inconnu
J'ai reçu: [$GPGSV,2,2,07,27,,,25,29,,,20,31,37,202,28*49]
Trame de type inconnu
J'ai reçu: [$GPGLL,,,,,134443.00,V,N*4F]
Trame de type inconnu
J'ai reçu: [$GPRMC,134444.00,V,,,,,,,070422,,,N*7C]
Trame de type RMC
J'ai reçu: [$GPVTG,,,,,,,,,N*30]
Trame de type inconnu
J'ai reçu: [$GPGGA,134444.00,,,,,0,00,99.99,,,,,,*64]
Trame de type GGA
J'ai reçu: [$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30]
Trame de type GSA
J'ai reçu: [$GPGSV,2,1,07,16,41,302,05,18,67,121,25,20,05,028,,26,76,292,29*7C]
Trame de type inconnu
J'ai reçu: [$GPGSV,2,2,07,27,,,25,29,,,19,31,37,202,28*43]
Trame de type inconnu
J'ai reçu: [$GPGLL,,,,,134444.00,V,N*48]
Trame de type inconnu

J'ai reçu: [$GPRMC,134443.00,V,,,,,,,070422,,,N*7B]
Trame de type RMC
J'ai reçu: [$GPVTG,,,,,,,,,N*30]
Trame de type inconnu
J'ai reçu: [$GPGGA,134443.00,,,,,0,00,99.99,,,,,,*63]
Trame de type GGA
J'ai reçu: [$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30]
Trame de type GSA
J'ai reçu: [$GPGSV,2,1,07,16,41,302,,18,67,121,25,20,05,028,,26,76,292,29*79]
Trame de type inconnu
J'ai reçu: [$GPGSV,2,2,07,27,,,25,29,,,20,31,37,202,28*49]
Trame de type inconnu
J'ai reçu: [$GPGLL,,,,,134443.00,V,N*4F]
Trame de type inconnu
J'ai reçu: [$GPRMC,134444.00,V,,,,,,,070422,,,N*7C]
Trame de type RMC
J'ai reçu: [$GPVTG,,,,,,,,,N*30]
Trame de type inconnu
J'ai reçu: [$GPGGA,134444.00,,,,,0,00,99.99,,,,,,*64]
Trame de type GGA
J'ai reçu: [$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30]
Trame de type GSA
J'ai reçu: [$GPGSV,2,1,07,16,41,302,05,18,67,121,25,20,05,028,,26,76,292,29*7C]
Trame de type inconnu
J'ai reçu: [$GPGSV,2,2,07,27,,,25,29,,,19,31,37,202,28*43]
Trame de type inconnu
J'ai reçu: [$GPGLL,,,,,134444.00,V,N*48]
Trame de type inconnu

Tout fonctionne bien JML...

OK bon début

la question maintenant est donc de savoir pour chaque type de trame d'intérêt (RMC, GGA et GSA), quels champs extraire (et où les trouver - mais ça n'importe quelle doc sur les Trames NMEA nous le dit)

votre code le fait sans doute mais il me paraît compliqué avec des tableaux de pointeurs etc... Je pense qu'on peut simplifier cela

const byte RXD2 = 16;
const byte TXD2 = 17;

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 = 100;
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;

void traiterMessage() {
  //Serial.print("J'ai reçu: [");
  //Serial.print(message);
  //Serial.println(']');

  if (strncmp(message, "$GPRMC", 6) == 0) {
    //Serial.println("Trame de type RMC");
    traitement(message, 1);
  }
  else if (strncmp(message, "$GPGGA", 6) == 0) {
    //Serial.println("Trame de type GGA");
    traitement(message, 2);
  }
  else if (strncmp(message, "$GPGSA", 6) == 0) {
    //Serial.println("Trame de type GSA");
    traitement(message, 3);
  }
  else {
    //Serial.println("Trame de type inconnu");
  }
  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);
}

bool messageRecu() {
  static byte indexMessage = 0;
  int r = Serial2.read();
  if (r != -1) { // on a reçu un caractère
    if (r == marqueurDeFin) {
      message[indexMessage] = '\0'; // on termine la c-string
      indexMessage = 0; // on se remet au début pour la prochaine fois
      return true;
    } else {
      if (indexMessage < tailleMessageMax) message[indexMessage++] = (char) r; // on stocke le caractère et on passe à la case suivante
    }
  }
  return false;
}

void setup() {
  Serial.begin(115200); Serial.println();
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2); // initialise la liaison RX1-TX1 sur espressif WROOM 32
  delay(100);
}

void loop() {
  if (messageRecu()) traiterMessage();
}

//=======================================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)));
  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;
}

donne :

latitude :46.9159206666667
longitude :0.5921036666667
altitude :51.6
Nb satellites :07
hdop :1.20
2022-04-07T14:07:07Z

Tout fonctionne parfaitement.

PS : au passage tout le monde sait où j'habite :smile:

bon si ça vous va, c'est super :slight_smile:

vous pouvez modifier quelques valeurs dans la lat/lon que vous postez :slight_smile:

Désolé mais après avoir débranché puis rebranché assez longtemps.
Le message revient jusqu'à initialisation du GPS :

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x400d0dea  PS      : 0x00060930  A0      : 0x800d0f4b  A1      : 0x3ffb1f00  
A2      : 0x00000000  A3      : 0x00000000  A4      : 0x3ffc035c  A5      : 0x402c1111  
A6      : 0x3ffc035c  A7      : 0x00000000  A8      : 0xef579ea1  A9      : 0x3ffb1ec0  
A10     : 0x3ffc005d  A11     : 0x3ffc006d  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: 0x400d0dea:0x3ffb1f00 0x400d0f48:0x3ffb1f50 0x400d0fc0:0x3ffb1f70 0x400d108f:0x3ffb1f90 0x400d19d9:0x3ffb1fb0 0x400860ed:0x3ffb1fd0

Rebooting...
ets Jun  8 2016 00:22:57

ça vient de mon code...

EDIT : ou de la plateforme - ESP32 ??

Ce n'est pas grave.

vous branchez dans quel ordre ?

installez GitHub - me-no-dev/EspExceptionDecoder: Exception Stack Trace Decoder for ESP8266 and ESP32 et décodez le message d'erreur, ça vous en dira un peu plus

le comportement est différent tout de même :

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x400d0dea  PS      : 0x00060930  A0      : 0x800d0f4b  A1      : 0x3ffb1f00  
A2      : 0x00000000  A3      : 0x00000000  A4      : 0x3ffc035c  A5      : 0x402c1111  
A6      : 0x3ffc035c  A7      : 0x3ffb0060  A8      : 0x62d133f0  A9      : 0x3ffb1ec0  
A10     : 0x3ffc005d  A11     : 0x3ffc006d  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: 0x400d0dea:0x3ffb1f00 0x400d0f48:0x3ffb1f50 0x400d0fc0:0x3ffb1f70 0x400d108f:0x3ffb1f90 0x400d19d9:0x3ffb1fb0 0x400860ed:0x3ffb1fd0

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:10124
load:0x40080400,len:5856
entry 0x400806a8

latitude :
longitude :
altitude :
Nb satellites :
hdop :

latitude :
longitude :
altitude :
Nb satellites :
hdop :

latitude :
longitude :
altitude :
Nb satellites :
hdop :

latitude :
longitude :
altitude :
Nb satellites :
hdop :

Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x400d0dea  PS      : 0x00060930  A0      : 0x800d0f4b  A1      : 0x3ffb1f00  
A2      : 0x00000000  A3      : 0x00000000  A4      : 0x3ffc035c  A5      : 0x402c1111  
A6      : 0x3ffc035c  A7      : 0x3ffb0060  A8      : 0x4bd743e4  A9      : 0x3ffb1ec0  
A10     : 0x3ffc005d  A11     : 0x3ffc006d  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: 0x400d0dea:0x3ffb1f00 0x400d0f48:0x3ffb1f50 0x400d0fc0:0x3ffb1f70 0x400d108f:0x3ffb1f90 0x400d19d9:0x3ffb1fb0 0x400860ed:0x3ffb1fd0

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:10124
load:0x40080400,len:5856
entry 0x400806a8

latitude :
longitude :
altitude :
Nb satellites :
hdop :

latitude :
longitude :
altitude :
Nb satellites :
hdop :

latitude :
longitude :
altitude :
Nb satellites :
hdop :

latitude :46.9161103333333
longitude :0.5921731666667
altitude :
Nb satellites :
hdop :
2022-04-07T14:22:49Z
latitude :46.9161103333333
longitude :0.5921731666667
altitude :
Nb satellites :
hdop :
2022-04-07T14:22:49Z
latitude :46.9161103333333
longitude :0.5921731666667
altitude :39.1
Nb satellites :04
hdop :
2022-04-07T14:22:49Z
latitude :46.9161103333333
longitude :0.5921731666667
altitude :39.1
Nb satellites :04
hdop :3.25
2022-04-07T14:22:49Z
latitude :46.9161103333333
longitude :0.5921731666667
altitude :39.1
Nb satellites :04
hdop :3.25
2022-04-07T14:22:49Z

ça arrive souvent quand on essaye de toucher à de la mémoire avec un mauvais pointeur.

est-ce que vous avez le pb avec mon code?

Non pas de soucis avec votre code...

OK donc il doit y avoir un souci dans la gestion de vos pointeurs

PC: 0x400d0e52: conversionDecimal(char*, bool) at D:\Utilisateur\Documents\Arduino\Test_05_04_2022_-_JML_2_c-string_bon/Test_05_04_2022_-_JML_2_c-string_bon.ino line 146
EXCVADDR: 0x00000000

Decoding stack results
0x400d0e52: conversionDecimal(char*, bool) at D:\Utilisateur\Documents\Arduino\Test_05_04_2022_-_JML_2_c-string_bon/Test_05_04_2022_-_JML_2_c-string_bon.ino line 146
0x400d0fb0: traitement(char*, int) at D:\Utilisateur\Documents\Arduino\Test_05_04_2022_-_JML_2_c-string_bon/Test_05_04_2022_-_JML_2_c-string_bon.ino line 98
0x400d1028: traiterMessage() at D:\Utilisateur\Documents\Arduino\Test_05_04_2022_-_JML_2_c-string_bon/Test_05_04_2022_-_JML_2_c-string_bon.ino line 32
0x400d10f7: loop() at D:\Utilisateur\Documents\Arduino\Test_05_04_2022_-_JML_2_c-string_bon/Test_05_04_2022_-_JML_2_c-string_bon.ino line 67
0x400d24e1: loopTask(void*) at D:\Utilisateur\Documents\ArduinoData\packages\esp32\hardware\esp32\1.0.6\cores\esp32\main.cpp line 23
0x40086125: vPortTaskWrapper at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/port.c line 143

Je vais y regarder. Je dois aller chercher ma voiture au garage...
Merci.

OK ça doit planter là dedans donc

Bon je viens d'y passer une heure mais je ne vois pas ce qui cloche.
Tout se passe bien dès que le GPS envoie les phrases complètes, tant qu'il n'est pas calé correctement il y a ces messages d'erreurs ! j'ai relu le code pour voir s'il était possible que je transmette des champs vides mais je ne pense pas que ce soit le cas !!!!
Comme vous le remarquez, il doit y avoir une mauvaise gestion dans mes pointeurs :cry: :cry: :cry:
Décidément rien n'est simple :cry:
Je pars en vacances demain, ça m'étonnerai que mes petits enfants me laissent du temps pour voir tout ça !!!!!
Je verrai ça à tête reposée à mon retour en espérant que je ferai preuve de plus de clairvoyance !

Merci JML
Bonne soirée.

Salut

Avant de faire le traitement de la phrase vérifiez que le check sum est bon.

dans ce petit sketch vous avez une fonction qui vous dit si c'est OK ou pas

char GPRMC[] = "$GPRMC,134443.00,V,,,,,,,070422,,,N*7B";
char GPGGA[] = "$GPGGA,134443.00,,,,,0,00,99.99,,,,,,*63";
char GPGSA[] = "$GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30";
char GPGSV[] = "$GPGSV,2,1,07,16,41,302,,18,67,121,25,20,05,028,,26,76,292,29*79";
char GPGLL[] = "$GPGLL,,,,,134443.00,V,N*4F";
char GPVTG[] = "$GPVTG,,,,,,,,,N*30";

char* phrases[] = {GPRMC, GPGGA, GPGSA, GPGSV, GPGLL, GPVTG};

bool phraseOK(const char *unePhrase) {
  byte cksum = 0;

  if (*unePhrase != '$') return false;          // une phrase commence toujours par $
  const char* starPtr = strchr(unePhrase, '*');
  if (starPtr != nullptr) {      // on a une étoile donc un CKSUM
    const char *ptr = unePhrase + 1;
    while (*ptr != '*') cksum ^= *ptr++;
    char *endPtr;
    unsigned long ckControl = strtoul (starPtr + 1, &endPtr, 16);
    return (*endPtr == '\0') && (cksum == ckControl);
  }
  return false; // pas d'étoile, donc pas de checksum à vérifier (ce qui est OK dans certains cas mais ici toutes nos phrases sont attendues avec un check sum)
}

void setup() {
  Serial.begin(115200); Serial.println();
  for (auto &p : phrases) {
    Serial.print(p);
    Serial.println(phraseOK(p) ? F(" -> est Correcte") : F(" -> est incorrecte"));
  }
}

void loop() {}

intégrez la fonction phraseOK() dans votre code, appelez là quand votre phrase est complète mais avant d'effectuer l'extraction des champs. peut être ça permettra de contourner le bug.


il se peut que le GPS envoie aussi le caractère \r avant le \n, il faut l'ignorer donc la fonction de réception serait

bool messageRecu() {
  static byte indexMessage = 0;
  int r = Serial2.read();
  if (r != -1) { // on a reçu un caractère
    if (r == marqueurDeFin) {
      message[indexMessage] = '\0'; // on termine la c-string
      indexMessage = 0; // on se remet au début pour la prochaine fois
      return true;
    } else {
      if ((r != '\r') && (indexMessage < tailleMessageMax))
        message[indexMessage++] = (char) r; // on stocke le caractère et on passe à la case suivante
    }
  }
  return false;
}

Merci beaucoup pour votre aide JML,
Je m'occupe de ça dans une dizaine de jours à mon retour de vacances.
J'arrête car ma femme me rappelle à mes devoirs d'homme marié :smile: !!!
Je sais pas comment est la votre mais la mienne, elle rigole pas …
Dommage car tout ça me passionne énormément :wink:

Merci infiniment et à très bientôt.

Profitez bien des vacances et des petits enfants !

Bonjour JML,
Voilà je vous rends ma copie qui concerne uniquement l'extraction et le formatage des champs utiles. Tout fonctionne parfaitement, je n'ai plus de message d'erreur :

Les phrases NMEA se forment dès l’initialisation du GPS. Si un champ n’est pas déterminé, il prendra le plus souvent une valeur vide entre les virgules où il doit se situer ; parfois il peut prendre la valeur 0 ou 99.99. Le croquis traite tous ces cas de figure de sorte qu’une valeur de champ ne puisse être traitée que si elle existe et est conforme. La fonction bool messageRecu() qui permet d’extraire les phrases, prend en compte le fait que chacune d’elles se termine d’abord par le caractère \r puis le caractère \n. S’il est établi qu’une phrase est reçue et que son check sum est correct, celle-ci est traitée (fonction loop). La fonction void traiterMessage() distingue les types de phrases (GPRMC…) puis les envoie à la fonction void extraire(char *message, int types) où chaque champ utile est extirpé puis formaté au format GPX (date et heure sont envoyés à la fonction char timeGpx(char *lesDates, char *lesHeures ) ; la latitude et la longitude sont envoyées à char* conversionDecimal (char *latlong, boolean lati) ).
Trois phrases sont traitées afin d’obtenir le minimum d’informations nécessaires à la constitution d’un fichier de type GPX :
1/ Phrases GPRMC dont on extrait avec la fonction : void extraire(char *message, int types) où message est la phrase et types le nombre de virgules + 1 :

  • L’heure ;
  • La validité des données ;
  • La latitude ;
  • La longitude ;
  • Et la date.

2/ Phrases GPGGA dont on extrait :

  • le nombre de satellites utilisés ;
  • l’altitude en mètres.

3/ Phrases GPGSA dont on extrait la dilution de précision horizontale.


// Selon JML Jackson

const byte RXD2 = 16;
const byte TXD2 = 17;

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';

char *variablesGpx[83];
char latitu [18], longitu[18];
char alti[18], sate[18], hdopss[18];
char dateHeure[25];
boolean reception = false;
const uint8_t ledPin = LED_BUILTIN;

// Déclaration des fonctions et procédures
bool messageRecu(); 
bool phraseOK(const char *unePhrase);
void traiterMessage();
void extraire(char *message, int types);
char timeGpx(char *lesDates, char *lesHeures );
char* conversionDecimal (char *latlong, boolean lati);
int NombreChiffreAVir (double ChiffreDec);
//}


void setup() {
  Serial.begin(115200); Serial.println();
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2); // initialise la liaison RX1-TX1 sur espressif WROOM 32
  pinMode(ledPin, OUTPUT);
  delay(100);
}

void loop() {
  if (messageRecu() && phraseOK(message) ) {
    traiterMessage();
  }
  Serial.println(latitu);
  Serial.println(longitu);
  Serial.println(dateHeure);
  Serial.println(alti);
  Serial.println(sate);
  Serial.println(hdopss);
  Serial.print('\n');
}
//====================================================================================
bool messageRecu() {
  static byte indexMessage = 0;
  int r = Serial2.read();
  if (r != -1) { // on a reçu un caractère
    if (r == marqueurDeFin) {
      message[indexMessage] = '\0'; // on termine la c-string
      indexMessage = 0; // on se remet au début pour la prochaine fois
      return true;
    } else {
      if ((r != '\r') && (indexMessage < tailleMessageMax))
        message[indexMessage++] = (char) r; // on stocke le caractère et on passe à la case suivante
    }
  }
  return false;
}
//================================================
bool phraseOK(const char *unePhrase) {
  byte cksum = 0;

  if (*unePhrase != '$') return false;          // une phrase commence toujours par $
  const char* starPtr = strchr(unePhrase, '*');
  if (starPtr != nullptr) {      // on a une étoile donc un CKSUM
    const char *ptr = unePhrase + 1;
    while (*ptr != '*') cksum ^= *ptr++;
    char *endPtr;
    unsigned long ckControl = strtoul (starPtr + 1, &endPtr, 16);
    return (*endPtr == '\0') && (cksum == ckControl);
  }
  return false; // pas d'étoile, donc pas de checksum à vérifier (ce qui est OK dans certains cas mais ici toutes nos phrases sont attendues avec un check sum)
}
//========================================================================
void traiterMessage() {

  //if (GPRMC(message)) {
  if (strncmp(message, "$GPRMC", 6) == 0) {
    extraire(message, 13);
    //    if (reception) {
    //      digitalWrite(ledPin, LOW);
    //    }
    //    else {
    //      digitalWrite(ledPin, HIGH);
    //      delay(200);
    //      digitalWrite(ledPin, LOW);
    //      delay(200);
    //    }
  }
  else if (strncmp(message, "$GPGGA", 6) == 0) {
    extraire(message, 15);
  }
  else if (strncmp(message, "$GPGSA", 6) == 0) {
    extraire(message, 18);
  }

}
//============================================================================
void extraire(char *message, int types) { // extrait les champs utiles des phrases GPRMC - GPGGA - GPGSA

  int nbVirgule = 0;
  char *valide;
  char *heures, *dates;
  char *latit, *longit;
  char *alt, *sat, *hdops;
  char* champNmea;


  for (int i = 0; i < types; i++) {
    champNmea = strsep(&message, ",");
    variablesGpx[nbVirgule++] = champNmea;
  }
  variablesGpx[nbVirgule] = '\0';

  if (types == 13) { //GPRMC
    heures = variablesGpx[1];
    valide = variablesGpx[2];
    latit = variablesGpx[3];
    longit = variablesGpx[5];
    dates = variablesGpx[9];

    if (*valide == 'A') { // Statut:  A = données valides, V = données non valides - 3eme champ des phrases NMEA de type GPRMC
      if (*heures != '\0' && *dates != '\0') { // on ne transmet pas de champs vides à la fonction timeGpx
        timeGpx(dates, heures);
      }
      if (*latit != '\0' && *longit != '\0') { // on ne transmet pas de champs vides à la fonction conversionDecimal
        conversionDecimal(latit, 1);
        conversionDecimal(longit, 0);
      }
      else {
        reception = false;

      }
    } // si statut vaut A

  }
  if (types == 15) { //GPGGA
    sat = variablesGpx[7];
    alt = variablesGpx[9];
    if (*sat != '\0' && atof(sat) != 0) sprintf(sate, "%s", sat); // on ne traîte pas de champs vides et de valeur égale à 0
    if (*alt != '\0' && atof(alt) != 0)  sprintf(alti, "%s", alt); // on ne traîte pas de champs vides et de valeur égale à 00

  }

  if (types == 18) { //GPGSA
    hdops = variablesGpx[16];
    if (*hdops != '\0' && atof(hdops) != 99.99 && atof(hdops) != 0) sprintf(hdopss, "%s", hdops); // on ne traîte pas un champ vide et de valeur égale à 0 et de  valeur = 99.99

  }

}
//=======================================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 degres[5];
  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)));
  reception = true;
  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;
}

Voilà.
Merci beaucoup pour votre aide précieuse. J'ai encore appris énormément ...