pb d'identification de caractère sur le port serie

Bonjour à tous,
Après une semaine sur mon pb je le soumet à vos yeux neufs et expérimentés.
Mon projet:
identifier des trames nmea reçues sur le port serie, en identifier une en particulier et en extraire une info pour envoyer une nouvelle trame sur la sortie serie.

Après avoir réécris, nettoyé, debuggé le code, ça marche (reste quelques vérifications tout de même).

Mais certaines trames de sont pas identifiées (via le "$" qui marque le début) alors que j'ai l'impression d'analyser un par un tous les caractères reçus sur le port série...
mon code:

#include <Wire.h>
#include <Adafruit_BMP085.h>
/* deuxième sketch pour IAS pour LK8000 dans une forme plus rigoureuse*/
//int ptot=1013; //à supprimer quand BMP085 dispo;
Adafruit_BMP085 bmp;
void setup(){
Serial.begin (57600);
bmp.begin();
}

void loop(){
Serial.println("loop");

while (int n=Serial.peek()!='$'){
if (Serial.available()<1){
continue;
}
Serial.print(char(Serial.read())); //penser à enlever le LN!
}
char nmea[83]={'$'};
get_nmea(nmea); //entre toute la trame dans la chaine nmea
if (get_entete(nmea)==true){ //si l'entete est celle qui donne la p_stat
Serial.println("if_loop true");
Serial.print("ptot "); Serial.print(bmp.readPressure()/100);Serial.println("hpa");
int ias=10sqrt((2((bmp.readPressure()/100) - get_pstat(nmea)))/1.225);
//calcul de l'IAS
Serial.print("IAS caculé est de: "); Serial.print(ias);Serial.println("dm/s");//penser à enlever le LN!
envoie_trame_ias(ias);

}else {
Serial.print("if loop false");
// Serial.print(nmea);
}
}

void get_nmea(char nmea[]){
// Serial.println("get_nmea");
for (int i=0; i<83; i++){
while (Serial.available()<1); // attente de 1 caractères dispo dans le buffer
nmea_=Serial.read(); //replissage de la chaine nmea avec les caratcères dispo_
_ if (nmea*==10){ //si le caractère est on arrête de remplir*_
* // Serial.print("caractere LF trouvé");*
* break; // et on quitte la boucle*
* }*
* }*
_ Serial.println(nmea); // on renvoie la trame sur la sortie serie //penser à enlever le LN!_
* return;*

}
boolean get_entete(char nmea[]){
* // Serial.print(nmea);*
* char entete_alti[8]="$PGRMZ,";
_
for (int i=0;i<6;i++){_
if(entete_alti_!=nmea){
// Serial.print("condition fausse");
return false;
}
}
return true;
}
[/quote]*

merci pour vos avis eclairés
Romaric_

mince j'avais viré toutes mes lignes de debug pour plus de lisibilité mais elles sont revenue...

#include <Wire.h>
#include <Adafruit_BMP085.h>
/* deuxième sketch pour IAS pour LK8000 dans une forme plus rigoureuse*/
//int ptot=1013; //à supprimer quand BMP085 dispo;
Adafruit_BMP085 bmp;
void setup(){
  Serial.begin (57600);
   bmp.begin(); 
}

void loop(){
  Serial.println("loop");
  
  while (Serial.peek()!='

){
    if (Serial.available()<1){
      continue;
    }
    Serial.print(char(Serial.read())); //penser à enlever le LN!
  }
  char nmea[83]={'


};
  get_nmea(nmea);  //entre toute la trame dans la chaine nmea
  if (get_entete(nmea)==true){  //si l'entete est celle qui donne la p_stat
    Serial.println("if_loop true");
    Serial.print("ptot "); Serial.print(bmp.readPressure()/100);Serial.println("hpa");
    int ias=10*sqrt((2*((bmp.readPressure()/100) - get_pstat(nmea)))/1.225);
         //calcul de l'IAS
    Serial.print("IAS caculé est de: "); Serial.print(ias);Serial.println("dm/s");//penser à enlever le LN!
    envoie_trame_ias(ias);
    
  }else {
    Serial.print("if loop false");
   // Serial.print(nmea);
  }
}

void get_nmea(char nmea[]){
 // Serial.println("get_nmea");
  for (int i=0; i<83; i++){
    while (Serial.available()<1);  // attente de 1 caractères dispo dans le buffer
    nmea[i]=Serial.read();  //replissage de la chaine nmea avec les caratcères dispo
    if (nmea[i]==10){  //si le caractère est <LF> on arrête de remplir
    //  Serial.print("caractere LF trouvé");
      break;                // et on quitte la boucle
    }
  }
  Serial.println(nmea);  // on renvoie la trame sur la sortie serie //penser à enlever le LN!
  return;
  
}
boolean get_entete(char nmea[]){
 // Serial.print(nmea);
  char entete_alti[8]="$PGRMZ,";
  for (int i=0;i<6;i++){
    if(entete_alti[i]!=nmea[i]){
     // Serial.print("condition fausse");
      return false;
    }
  }
  return true;
  }

Bonjour

La fonction get_entete() comporte une légère erreur : tu boucles de 0 à 5 donc tu ne compare que 6 caractère soit "$PGRM"
Il manque le Z et la virgule. Ce qui n'est pas forcement un problème.
Mais pourquoi s'embeter alors qu'il existe strncmp()

Sans avoir testé le code, en simple lecture directe je ne vois rien de choquant même si je ne l'aurais pas écris comme cela.

Par ailleurs tu te sers de la liaison série à la fois pour le debug vers le PC et pour la liaison avec le GPS. Il se peut que les problèmes viennent de là.

ah oui tiens,
c'est parceque au début, je ne lisais que "PGRMZ" j'ai pas correctement modifié le test.
Pour strncmp(), je ne suis qu'un débutant en C, j'utilise mes restes de "BASIC" de la fin des années 90 :slight_smile: et là c'est déjà bien mieux que la première version avec pleins de variables à porté général (j'ai potassé les pointeurs) mais c'est prévu pour la suite, tout comme l'utilisation de sscanf() pour extraire mon info (pour l'instant c'est aussi une boucle faite maison),une fois que j'aurai trouvé mon pb.

Mais c'est vrai que sur le fond ça ne change rien, ça ne devrait pas laisser passer de trame au travers. pour moi le mystère demeure.

Pour le debug, je n'utilise pour l'instant que le terminal série pour envoyer les trames, recevoir des infos pour debug et voir ce qui serait envoyé réellement.

Autre étonnement: Serial.peek() me pose qq soucis: dans le tout début pas de pb, le caractère reste et le serial.read le retrouve. Mais lorsque le "$" arrive, la boucle de remplissage de ma chaine commence et Serial.read() lit direct le caractère suivant dans la file. Je doit entrer "$" manuellement au début de ma chaine pour contourner ça et ça fait pas très propre...

Je vais essayer de corriger ces petites ratures et voir.
Merçi
Romaric

en bonus le: reste du code XD

int get_pstat(char nmea[]){
char char_pstat[7]={'\0'};
int pstat;
for (int i=7 ; nmea*!=',' ; i++){*
char_pstat[i-7]=nmea*;
_
}_
// Serial.print(char_pstat);Serial.println("pieds");
pstat= atoi(char_pstat);
_
// Serial.print(pstat);Serial.println("pieds");_
_ pstat=1013.25 * pow((288-(0.0065pstat0.3028))/288,5.255); //formule de conversion pieds en hpa_
_ // Serial.print("pstat "); Serial.print(pstat); Serial.println("hPa");_
_
return pstat;_
_
}_
void envoie_trame_ias(int ias){
// Serial.println("envoie trame ias");
char char_ias[4]={'\0'};
char char_nmea_ias[15]="$PLKAS,";
_
int n;_
itoa (ias,char_ias,10);*

// Serial.print("char_ias: "); Serial.println(char_ias);

* for (int i=7; char_ias[i-7]!='\0';i++){
char_nmea_ias=char_ias[i-7];
_ n=i;
// Serial.print("i= "); Serial.println(i);
}_
char_nmea_ias[n+1]=',';
_ / char XOR=0;
for (int i=0; char_nmea_ias*!='\0';i++){[/color]
XOR^=char_nmea_ias;[/color]*

}/_
char_nmea_ias[n+2]=get_XOR(char_nmea_ias);
char_nmea_ias[n+3]=13;
char_nmea_ias[n+4]=10;
Serial.print (char_nmea_ias);
_ return;
}
char get_XOR(char trame[]){
// Serial.println("get_XOR");
char XOR='\0';
for (int i=0; trame!='\0';i++){
XOR^=trame;
}
return XOR;
}
[/quote]*_

En fait je pense que le problème vient justement du peek

Essaye quelque chose comme cela :

while ( Serial.available() )
{
   char c = Serial.read();
   if ( c == '

Regarde aussi dans mon tuto sur les protocoles de communication. Je défini un protocole qui est quasiment identique au NMEA et j'utilise un automate pour gérer la réception avec timeout etc ....
)
  {
      nmea[0] = c;
      ....
  }
}


Regarde aussi dans mon tuto sur les protocoles de communication. Je défini un protocole qui est quasiment identique au NMEA et j'utilise un automate pour gérer la réception avec timeout etc ....

Un doute dans ta fonction :

boolean get_entete(char nmea[]){
 // Serial.print(nmea);
  char entete_alti[8]="$PGRMZ,";
  for (int i=0;i<6;i++){
    if(entete_alti!=nmea){
     // Serial.print("condition fausse");
      return false;
    }
  }
  return true;
}

Tu compares entete_alti != nmea dans la boucle, mais tu compares les deux tableaux en entier, ce qui fait que comme ils n'ont pas la même taille, le résultat devrait être faux dès le départ, non?

Je l'écrirais comme ceci :

boolean get_entete(char nmea[]){
 // Serial.print(nmea);
  char entete_alti[8]="$PGRMZ,";
  for (int i=0;i<8;i++){
    if(entete_alti[i]!=nmea[i]){
     // Serial.print("condition fausse");
      return false;
    }
  }
  return true;
}

J'ai modifié le for : de i = 0 à 7 pour comparer les 8 premiers caractères, ainsi que la comparaison pour comparer des caractères et non pas des tableaux de caractères...

Voilà...

oui j'ai vu ça mais les sont bien dans le code...
merci
à présent:
je n'utilise plus serial.peek et il n'y a plus pb de caractère raté.
Dommage je trouvais ça plus élégant que la methode du caractère intermédiaire mais ça ne fonctionne pas (une limitation de peek?).
j'ai avancé.
Maintenant je suis sur le crc32 de la chaine que j'envoie (c'est pas un xor).
romaric

Le peek() récupère le premier caractère de la file d'attente mais ne fait pas avancer le pointeur.
Donc si derrière tu n'effectue pas de read() le pointeur n'avance pas et le peek() retourne toujours le même caractère.

Ca marche peut être la 1ere fois et tant que tu retombe juste sur '$' mais si tu rate un caractère, tout se bloque.

ok je viens de piger: je ne maitrise encore pas totalement le forum :grin:
[i]sans balise particulière n'apparait pas (comme dans mon message précédant ou je l'ai pourtant bien écrit).

Pour le peek. dans les deux cas il était suivit d'un Serial.read: dans un cas en direct et dans l'autre cas dans la fonction appélée.
Pas grave j'ai maintenant utilisé la méthode qui fonctionne. :slight_smile:

Romaric

c'est bon,
tout marche parfaitement bien maintenant.
J'utilise le connecteur USB depuis mon PC ainsi que les i/o série vers mon PNA via un cable micro USB en mode serie (pas USB) et il n'y a pas de problème particulier.
Etape suivante: accélérer le calcul.
Merci,
à bientôt
Romaric