Module GPS (Goouuu Tech GT-U7)

J'ai acheté (10€) un petit module de réception GPS dans l'idée d'indiquer quelques données (heure, date, position, vitesese...) sur un afficheur.

J'ai commencé par essayer d'aller récupérer un programme tout fait.
Pas de chance, ça marche pas et mes connaissances ne sont pas encore assez fortes pour comprendre pourquoi.
Et puis, je ne trouve pas très satisfaisant (intellectuellementparlant) d'utiliser du tout-cuit sans comprendre comment ça marche.

Donc, pas le choix: obligé de mettre les mains dans le cambouis.
Je vous tiens au courant de mes avancées au fur et à mesure.

Première étape:
Je sort l'oscillo et je regarde ce qui passe sur la pin TX
Au bout d'un moment, on commence à avoir quelque chose.
Jaune: TX Bleu: PPS

Important à savoir: comme on travaille à l'intérieur le module mets un certain temps (parfois un bon quart d'heure) avant de recevoir des données et de les retransmettre.
L'idéal est de câbler la pin PPS (pulse per second) sur une résistance-LED (trace bleue sur l'oscillo).
Tant que la LED ne clignote pas, c'est qu'il n'y a rien à voir.

Une fois les bons paramètres trouvés, on identifie bien un signal UART.
9600 bauds, LSB, 8 bits de donnée, 1 bit de stop, pas de parité.


Le texte $GPRMC est encourageant et 122500 pourrait bien être l'heure.
On progresse.

Deuxième étape:
On câble le signal TX du GPS sur RX1 du l'Arduino.
Comme tout débutant je suis tombé dans le panneau: il ne faut pas câbler sur RX sinon on entre en conflit avec la liaison série du PC.
Un petit programme pour écouter la trame reçue sur RX1

//+++++ VARIABLES
char OctetEntrant = 0; // Octet entrant par RX1

//+++++ INITIALISATION ( SETUP )
void setup()
{
  // Initialisation des liaisons série
  Serial.begin(9600);  // initialise la liaison PC
  Serial1.begin(9600); // initialise la liaison RX1   
}

//+++++ PROGRAMME PRINCIPAL ( LOOP )
void loop()
{
  if (Serial1.available() > 0)
  {
    OctetEntrant = Serial1.read();     // Lire l'octet entrant
    Serial.print(OctetEntrant);        // Afficher l'octet
  }
}

Bingo! Le texte reçu ressemble à ça:
"
$GPRMC,181449.00,A,4908.96178,N,00015.39852,W,2.258,,200222,,,A6B
$GPVTG,,T,,M,2.258,N,4.182,K,A
21
$GPGGA,181449.00,4908.96178,N,00015.39852,W,1,04,2.61,49.3,M,45.8,M,,7C
$GPGSA,A,3,23,27,08,18,,,,,,,,,4.30,2.61,3.41
03
$GPGSV,3,1,10,05,02,023,,07,08,331,18,08,16,276,27,10,20,149,207F
$GPGSV,3,2,10,18,50,059,22,23,35,117,14,26,57,166,19,27,49,282,18
7A
$GPGSV,3,3,10,29,05,085,,31,00,189,79
$GPGLL,4908.96178,N,00015.39852,W,181449.00,A,A
7F
$GPRMC,181450.00,A,4908.96180,N,00015.39825,W,1.320,,200222,,,A69
$GPVTG,,T,,M,1.320,N,2.445,K,A
24
$GPGGA,181450.00,4908.96180,N,00015.39825,W,1,04,2.61,48.6,M,45.8,M,,77
$GPGSA,A,3,23,27,08,18,,,,,,,,,4.30,2.61,3.41
03
$GPGSV,3,1,10,05,02,023,,07,08,331,18,08,16,276,27,10,20,149,207F
$GPGSV,3,2,10,18,50,059,22,23,35,117,12,26,57,166,19,27,49,282,18
7C
$GPGSV,3,3,10,29,05,085,,31,00,189,79
$GPGLL,4908.96180,N,00015.39825,W,181450.00,A,A
70
"
On identifie une trame conforme à la norme NMEA 0183 (National Marine Electronics Association).
Il ne reste plus qu'à analyser cette norme puis à extraire les données de ce foutoir.

Il va falloir que je travaille les instructions de manipulation des chaines de texte.
Si certains d'entre vous ont des aides ou touts à me conseiller sur ce sujet, merci d'avance.

Salut.
As-tu essayé la librairie TinyGPS, et ses exemples ?

Si elle n'est pas adaptée, s'inspirer du code.

La norme NMEA pour ceux que ça intéresse
NMEA0183.pdf (58,7 Ko)

Bonjour @olaf_grossebaf ,

Vous initialisez Serial1 avec la bibliothèque SoftwareSerial.h ?

La diode rouge sur le GT-U7 ne fait elle pas la même chose ? Elle clignote en même temps que ma led connectée à sa pin PPS.

Merci par avance.

J'ai réussi à faire fonctionner ce module en utilisant la deuxième bibliothèque de @hbachetti
Il suffit juste de modifier le débit de la liaison série gérant le module on passe de 4800 en 9600 bit/s.

static const uint32_t GPSBaud = 9600;

Bonne journée.

1 Like

Vous initialisez Serial1 avec la bibliothèque SoftwareSerial.h ?

Bonjour.
Non, je n'utilise rien de spécial.
Pourquoi, tu penses que ça pourrait changer quelque chose ?
En tout cas, ça semble fonctionner sans ça.

La diode rouge sur le GT-U7 ne fait elle pas la même chose ? Elle clignote en même temps que ma led connectée à sa pin PPS.

C'est vrai qu'elle clignote en même temps bien qu'en opposition de phase.
Je l'ai câblé sur une entrée en me disant qu'elle pourrait servir à déclencher la lecture des trames, mais ça reste à voir.

philippe86220
J'ai réussi à faire fonctionner ce module en utilisant la deuxième bibliothèque de @hbachetti
Il suffit juste de modifier le débit de la liaison série gérant le module on passe de 4800 en 9600 bit/s.

Merci pour l'info, il faut que j'aille regarder de ce coté.
L'ennui c'est que je découvre le C++ au fur et à mesure; j'ai encore du mal à comprendre ces histoires de bibliothèque et à analyser leur contenu.

C'est bête parce que le problème n'est pas très compliqué.
Il suffit juste de repérer les suites "$GPRMC" dans la trame entrante et d'enregistrer les 53 caracères qui suivent.

Quand je fais

void loop()
{
  if (Serial1.available() > 0)
  {
    InChar = Serial1.read();     // Lire l'octet entrant
    if(InChar == '$')             // Attend un début de ligne
    {
      Serial.print(InChar);
    }
  }
}

J'obtiens bien une suite "$$$$$$$$$$$$$$$$$$"
J'ai filtré les "$"

Si je fais

void loop()
{
  if (Serial1.available() > 0)
  {
    InChar = Serial1.read();     // Lire l'octet entrant
    if(InChar == '$')             // Attend un début de ligne ($)
    {
      Serial.print(InChar);
    }
    if(InChar == 'G')             // Attend un G
    {
      Serial.print(InChar);
    }
  }
}

J'obtiens bien une suite "$G$GGG$GG$GG$GG$GG$GG$G$GG$GGG$G"
J'ai filtré les "$" et les "G"

Par contre, si je fais

void loop()
{
  if (Serial1.available() > 0)
  {
    InChar = Serial1.read();     // Lire l'octet entrant
    if(InChar == '$')             // Attend un début de ligne ($)
    {
      Serial.print(InChar);
    }
    InChar = Serial1.read();     // Lire l'octet entrant
    if(InChar == 'G')             // Attend un G
    {
      Serial.print(InChar);
    }
  }
}

J'obtiens à nouveau une suite "$$$$$$$$$$$$$$$$$$"
J'ai perdu les "G"
Comme si le deuxième Serial1.read() fichait le bazar.

Mais quel est donc cet étrange mystère ?

A force de tâtonner et d'essayer de contourner les problèmes j'ai fini par faire ça:

void EcouteGPS()
{
  if(Serial1.read() == '$')             // Attend un début de ligne
  {
    Serial1.readBytes(IdentLigne, 5);  // Lire 5 caractères suivants
    if((IdentLigne[0] == 'G')          // Tester si entête NMEA = "GPRMC"
    && (IdentLigne[1] == 'P')
    && (IdentLigne[2] == 'R')
    && (IdentLigne[3] == 'M')
    && (IdentLigne[4] == 'C'))
    {
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(Heure, 2);        // heure
      Serial1.readBytes(Minute, 2);       // minutes
      Serial1.readBytes(Seconde, 2);      // secondes
      Serial1.readBytes(Poubelle, 1);     // élimine le point
      Serial1.readBytes(CentiSeconde, 2); // centièmes de seconde
      Serial1.readBytes(Poubelle, 3);     // élimine 3 caractères status
      Serial1.readBytes(DegLat, 2);       // degrés de latitude
      Serial1.readBytes(MinLat, 2);       // minutes de latitude
      Serial1.readBytes(Poubelle, 1);     // élimine le point
      Serial1.readBytes(CMilLat, 5);      // centmillième de minutes de latitude
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(LatNS, 1);        // Nord/Sud
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(DegLon, 3);       // degrés de longitude
      Serial1.readBytes(MinLon, 2);       // minutes de longitude
      Serial1.readBytes(Poubelle, 1);     // élimine le point
      Serial1.readBytes(CMilLon, 5);      // centmillième de minutes de longitude
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(LonEW, 1);        // Est/Ouest
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(VSol, 5);         // vitesse sol (noeuds)
      Serial1.readBytes(Poubelle, 2);     // élimine 3 caractères track made
      Serial1.readBytes(Jour, 2);         // jour
      Serial1.readBytes(Mois, 2);         // mois
      Serial1.readBytes(Annee, 2);        // année
      EchoConsole();
    }
  }  
}

C'est surement pas très élégant, mais ça fonctionne.
Il manque quand même les vérifications en cas de trame erronée !

Bonjour,
Désolé pour ma réponse tardive, je n'ai pas beaucoup de temps en ce moment.
Non ça ne change rien. C'est juste que sur certaines plateformes il n'y a pas plusieurs liaisons série d'où l'utilité de la bibliothèque SoftwareSerial.h.
Je suis très intéressé par vos recherches. Pouvez-vous poster l'ensemble de votre code ?
Merci et bonne journée.

C'est juste que sur certaines plateformes il n'y a pas plusieurs liaisons série d'où l'utilité de la bibliothèque SoftwareSerial.h

En effet, comme je teste sur un Mega2560 je n'en ais pas besoin.
Le problème risque de se poser quand je ferai le transfert sur un AT328P.

Pouvez-vous poster l'ensemble de votre code ?

Mais bien sûr, avec plaisir.
Je précise juste que c'est une version provisoire.
Pour le moment je récupère les infos GPS et je les affiche sur la console série.
Reste à faire l'affichage sur autre chose (écran LCD, digits LED...).

//*****
//     DECODEUR signal GPS
//      Entrée: Module GPS Goouuu Tech GT-U7
//      Sortie: Console série PC
//
// Francois Lambert @ F14630  2022          
//*****

//+++++ BIBLIOTHEQUES

//+++++ ENTREES SORTIES

// Signal UART venant du GPS: RX1 (pin 19) sur Mega2560

//+++++ CONSTANTES

//+++++ VARIABLES

char IdentLigne[6]; // 5 premiers caractères de la ligne = Talker + Sentence Identifier NMEA
char Poubelle[4];  // Caractères inutilisés
char Heure[3]; // Heure
char Minute[3]; // Minute
char Seconde[3]; // Seconde
char CentiSeconde[3]; // Centième de seconde
char DegLat[3]; // Degrés de latitude
char MinLat[3]; // Minutes de latitude
char CMilLat[6]; // Centmillème de latitude
char LatNS[2];  // Nord/Sud
char DegLon[4]; // Degrés de longitude
char MinLon[3]; // Minutes de longitude
char CMilLon[6]; // Centmillème de longitude
char LonEW[2];  // Est/Ouest
char VSol[6];  // Vitesse sol (noeuds)
char Jour[3];  // Jour
char Mois[3];  // Mois
char Annee[3];  // Année

//+++++ OBJECTS

//+++++ INITIALISATION ( SETUP )
void setup()
{
  // Eteindre la LED interne  
  pinMode(LED_BUILTIN, OUTPUT);    // Sortie Led interne en STOR
  digitalWrite(LED_BUILTIN, LOW);  // OFF

  // Initialisation des liaisons série
  Serial.begin(9600);  // initialise la liaison PC
  Serial1.begin(9600); // initialise la liaison RX1   
}

//+++++ PROGRAMME PRINCIPAL ( LOOP )
void loop()
{
  if (Serial1.available() > 0)
  {
    EcouteGPS();
  }
}

//+++++ FONCTIONS

// Ecouter les trames venant du GPS et extraire les infos intéressantes
void EcouteGPS()
{
  if(Serial1.read() == '$')             // Attend un début de ligne
  {
    Serial1.readBytes(IdentLigne, 5);  // Lire 5 caractères suivants
    if(strcmp(IdentLigne, "GPRMC") == 0)  // test chaine de caractères
    {
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(Heure, 2);        // heure
      Serial1.readBytes(Minute, 2);       // minutes
      Serial1.readBytes(Seconde, 2);      // secondes
      Serial1.readBytes(Poubelle, 1);     // élimine le point
      Serial1.readBytes(CentiSeconde, 2); // centièmes de seconde
      Serial1.readBytes(Poubelle, 3);     // élimine 3 caractères status
      Serial1.readBytes(DegLat, 2);       // degrés de latitude
      Serial1.readBytes(MinLat, 2);       // minutes de latitude
      Serial1.readBytes(Poubelle, 1);     // élimine le point
      Serial1.readBytes(CMilLat, 5);      // centmillième de minutes de latitude
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(LatNS, 1);        // Nord/Sud
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(DegLon, 3);       // degrés de longitude
      Serial1.readBytes(MinLon, 2);       // minutes de longitude
      Serial1.readBytes(Poubelle, 1);     // élimine le point
      Serial1.readBytes(CMilLon, 5);      // centmillième de minutes de longitude
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(LonEW, 1);        // Est/Ouest
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(VSol, 5);         // vitesse sol (noeuds)
      Serial1.readBytes(Poubelle, 2);     // élimine 3 caractères track made
      Serial1.readBytes(Jour, 2);         // jour
      Serial1.readBytes(Mois, 2);         // mois
      Serial1.readBytes(Annee, 2);        // année
      EchoConsole();
    }
  }  
}

// Imprime les infos GPS extraites sur la console
void EchoConsole()
{
  Serial.print("Heure = ");
  Serial.print(Heure); Serial.print(":"); 
  Serial.print(Minute); Serial.print(":");
  Serial.print(Seconde); Serial.print(",");
  Serial.print(CentiSeconde);
  Serial.print(" TU Latitude = ");
  Serial.print(DegLat); Serial.print("°");
  Serial.print(MinLat); Serial.print("'");
  Serial.print(CMilLat); Serial.print(" ");
  Serial.print(LatNS);
  Serial.print(" Longitude = ");
  Serial.print(DegLon); Serial.print("°");
  Serial.print(MinLon); Serial.print("'");
  Serial.print(CMilLon); Serial.print(" ");
  Serial.print(LonEW);
  Serial.print(" Vitesse = ");
  Serial.print(VSol); Serial.print(" Nds");
  Serial.print(" Date = ");
  Serial.print(Jour); Serial.print("/");
  Serial.print(Mois); Serial.print("/20");
  Serial.print(Annee); Serial.println("");
}

Je précise quand même deux choses:

  1. Pour le moment, il n'y a pas de contrôle d'erreur.
    C'est pas très gênant vu qu'il s'agit juste d'un affichage.
    Si c'est pour guider un drone par exemple, ça risque d'être beaucoup plus casse-gueule.

  2. Je ne l'ai testé qu'en statique, sur mon bureau.
    A voir si, en mouvement y'aurais pas un cafouillage
    (je pense à l'info "8) Track made good" qui reste muette pour l'instant)

Merci @olaf_grossebaf pour le code.
Le module GPS Tech GT-U7 est très performent, je l'ai testé en voiture et la précision était au rendez-vous par contre il est très fragile ! J'ai voulu le souder sur une plaque à souder mais il n'a pas trop apprécié la chaleur. Du coup j'en ai commandé un autre et je l'attends pour pouvoir tester votre code.

Bonne journée.

Il peut parfois être trèèèèèèès long à faire un fix.
Donc essayer au maximum de le garder sous tension.

Bonsoir @olaf_grossebaf ,
J’ai reçu mon nouveau module GPS et j’ai testé votre code, il fonctionne bien sur un ESP 32 (VROOM 32 version avec un RX2 et un TX2).

A/ Concernant votre premier programme :
1/ toutes les trames ou phrases NMEA 0183 apparaissent correctement dans le moniteur série dés lors que le module est opérationnel : $GPRMC - $GPVTG - $GPGGA - $GPGSA - $GPGSV- $GPGSV - $GPGSV $GPGLL.
2/ Elles sont conformes et parfaitement exploitables.

B/ Concernant votre deuxième programme :
Vous avez choisi d’extraire la trame GPRMC (données minimales exploitables spécifiques) et là aussi votre code fonctionne bien avec mon matériel.
On pourrait très bien envisager de transformer la latitude et la longitude au format décimal de manière à pouvoir exploiter directement les données dans le logiciel maps ou autre … Si mes souvenirs sont bons, il suffit de diviser les secondes par 60 et d’ajouter le résultat aux degrés. Il est également simple d’enregistrer les données sur une carte SD. Bref les possibilités d’évolutions sans passer par les bibliothèques existantes sont nombreuses !
Merci pour ce code facilement compréhensible et efficace.

Excellente remarque, J'ai débuté sur arduino, langage C et électronique depuis le dernier confinement. Donc moi aussi je débute et je pense comme vous que le meilleur moyen de progresser est d'apprendre par soi même ! Plus on utilise le code des autres, plus c'est simple mais moins on comprend et moins on évolue.

Merci encore.

PS : Je pars 10 jours pour m'occuper de mon papa. Du coup je ne vais pas avoir beaucoup de temps mais je vais travailler sur votre projet et je ne manquerai pas de vous faire part de mon code.

Bonjour @olaf_grossebaf,
Voilà, j'ai modifié votre programme de sorte qu'il se contente d'extraire les phrases GPRMC afin de les enregistrer sur une carte SD au format txt. Ensuite il suffit par exemple d'aller sur le site gpsvisualizer pour convertir ce fichier au format GPX. Enfin par exemple sur ce site : maplorer, vous pouvez visualiser votre parcours. J'ai également rajouter un écran LCD pour visualiser votre position, la date et l'heure. Les données ne sont traitées que si elles sont valides char etat[2]; // Etat A=donnees valides, V=donnees invalides (il faudrait voir également du côté du checksum pour vérifier leur conformité).
Voilà, j'ai fait ça très rapidement et je l'ai testé, ça fonctionne parfaitement.
Le matériel : Expressif WROOM 32 + écran LCD 2004 (trop gros mais I2C, il faudrait tester avec un TFT) + lecteur SD basique + GPS.

//*****
//     DECODEUR signal GPS
//      Entrée: Module GPS Goouuu Tech GT-U7
//      Sortie: Console série PC
//
// Francois Lambert @ F14630  2022
//*****
//+++++ BIBLIOTHEQUES
#include <SD.h>
#include <LiquidCrystal_I2C.h>

//+++++ ENTREES SORTIES

// Signal UART venant du GPS: RX1 (pin 19) sur Mega2560

//+++++ CONSTANTES
const int   sdCardPinChipSelect     = 5;    // Le lecteur de carte SD sera branché sur la pin 5 pour le CS (chip select) pour  le  bus SPI
//+++++ VARIABLES
String phrase;
char IdentLigne[6]; // 5 premiers caractères de la ligne = Talker + Sentence Identifier NMEA
char Poubelle[4];  // Caractères inutilisés
char Heure[3]; // Heure
char Minute[3]; // Minute
char Seconde[3]; // Seconde
char CentiSeconde[3]; // Centième de seconde
char etat[2]; // Etat A=donnees valides, V=donnees invalides
char DegLat[3]; // Degrés de latitude
char MinLat[3]; // Minutes de latitude
char CMilLat[6]; // Centmillème de latitude
char LatNS[2];  // Nord/Sud
char DegLon[4]; // Degrés de longitude
char MinLon[3]; // Minutes de longitude
char CMilLon[6]; // Centmillème de longitude
char LonEW[2];  // Est/Ouest
char VSol[6];  // Vitesse sol (noeuds)
char Jour[3];  // Jour
char Mois[3];  // Mois
char Annee[3];  // Année
char somme[5];// Somme de contrôle de parité au format hexadécimal

//+++++ OBJECTS
LiquidCrystal_I2C lcd(0x27, 20, 4);
File monFichier;

//+++++ DECLARATION DES FONCTIONS 
void EcouteGPS(void);
void enregistrement(void);

//+++++ INITIALISATION ( SETUP )
void setup()
{
  //initialise l ecran LCD
  lcd.init();
  lcd.backlight();
  lcd.clear();

  // Eteindre la LED interne
  pinMode(LED_BUILTIN, OUTPUT);    // Sortie Led interne en STOR
  digitalWrite(LED_BUILTIN, LOW);  // OFF

  // Initialisation des liaisons série
  Serial.begin(9600);  // initialise la liaison PC
  Serial1.begin(9600, SERIAL_8N1, 16, 17); // initialise la liaison RX1-TX2
}

//+++++ PROGRAMME PRINCIPAL ( LOOP )
void loop()
{
  if (Serial1.available() > 0)
  {
    EcouteGPS();
  }
  // ----------------------------------------------------------------------------
  // Vérification : est-ce que la carte SD est bien accessible depuis l'arduino ?
  // ----------------------------------------------------------------------------
  if (!SD.begin(sdCardPinChipSelect)) {
    Serial.println("Erreur carte SD!");
    return;
  }
}

//+++++ FONCTIONS

// Ecouter les trames venant du GPS et extraire les infos intéressantes
void EcouteGPS()
{
  if (Serial1.read() == '$')            // Attend un début de ligne
  {
    Serial1.readBytes(IdentLigne, 5);  // Lire 5 caractères suivants
    if (strcmp(IdentLigne, "GPRMC") == 0) // test chaine de caractères
    {
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(Heure, 2);        // heure
      Serial1.readBytes(Minute, 2);       // minutes
      Serial1.readBytes(Seconde, 2);      // secondes
      Serial1.readBytes(Poubelle, 1);     // élimine le point
      Serial1.readBytes(CentiSeconde, 2); // centièmes de seconde
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(etat, 1);         // Etat A=donnees valides, V=donnees invalides
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(DegLat, 2);       // degrés de latitude
      Serial1.readBytes(MinLat, 2);       // minutes de latitude
      Serial1.readBytes(Poubelle, 1);     // élimine le point
      Serial1.readBytes(CMilLat, 5);      // centmillième de minutes de latitude
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(LatNS, 1);        // Nord/Sud
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(DegLon, 3);       // degrés de longitude
      Serial1.readBytes(MinLon, 2);       // minutes de longitude
      Serial1.readBytes(Poubelle, 1);     // élimine le point
      Serial1.readBytes(CMilLon, 5);      // centmillième de minutes de longitude
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(LonEW, 1);        // Est/Ouest
      Serial1.readBytes(Poubelle, 1);     // élimine la virgule
      Serial1.readBytes(VSol, 5);         // vitesse sol (noeuds)
      Serial1.readBytes(Poubelle, 2);     // élimine 2 virgules
      Serial1.readBytes(Jour, 2);         // jour
      Serial1.readBytes(Mois, 2);         // mois
      Serial1.readBytes(Annee, 2);        // annee
      Serial1.readBytes(Poubelle, 3);     // élimine 3 virgules
      Serial1.readBytes(somme, 4);        // Somme de contrôle de parité au format hexadécimal
      if (strcmp(etat, "A") == 0) { // on ne traite les donnees que si elles sont valides
        EchoConsole();
        enregistrement();
        phrase = "";
      }
    }
  }
}

// Imprime les infos GPS extraites sur la console
void EchoConsole()
{ // consrtruction phrase GPRMC
  phrase += '$'; phrase += IdentLigne; phrase += ',';
  phrase += Heure; phrase += Minute; phrase += Seconde; phrase += '.'; phrase += CentiSeconde; phrase += ','; // Heure UTC
  phrase += etat; phrase += ','; // Etat A=donnees valides, V=donnees invalides
  phrase += DegLat; phrase += MinLat; phrase += '.'; phrase += CMilLat; phrase += ','; phrase += LatNS; phrase += ','; // Latitude
  phrase += DegLon; phrase += MinLon; phrase += '.'; phrase += CMilLon; phrase += ','; phrase += LonEW; phrase += ','; // Longitude
  phrase += VSol; phrase += ",,"; // Vitesse sol (noeuds)
  phrase += Jour; phrase += Mois; phrase += Annee; phrase += ",,,"; // date
  phrase += somme;
  Serial.println(phrase);

  //Affichage LCD
  lcd.setCursor(0, 0);
  lcd.print(DegLat); lcd.write((char)223);
  lcd.print(MinLat); lcd.print("'");
  lcd.print(CMilLat); lcd.print(" "); lcd.print(LatNS);
  lcd.setCursor(0, 1);
  lcd.print(DegLon); lcd.write((char)223);
  lcd.print(MinLon); lcd.print("'");
  lcd.print(CMilLon); lcd.print(" "); lcd.print(LonEW);
  lcd.setCursor(0, 2);
  lcd.print(Heure); lcd.print(":");
  lcd.print(Minute); lcd.print(":");
  lcd.print(Seconde); lcd.print(" UTC");
  lcd.setCursor(0, 3);
  lcd.print(Jour); lcd.print("/");
  lcd.print(Mois); lcd.print("/20");
  lcd.print(Annee);
}

// Enregistrement de ces données sur la carte SD
void enregistrement() {
  monFichier = SD.open("/gps.txt", FILE_APPEND);
  if (monFichier) {
    monFichier.println(phrase);
    monFichier.close();                     // L'enregistrement des données se fait au moment de la clôture du fichier
    Serial.println("  Enregistrement réussi sur carte SD");
  }
  else {
    Serial.println("  Erreur lors de la tentative d'ouverture du fichier en écriture, sur la carte SD");
  }
}

Bonne journée.