Traitement chaine de caracteres depuis le port série

Bonjour,
je cherche à traiter une chaine de caractères et exclusivement celle-ci, provenant du port série d'un UNO. Ce formatage répond à la norme NMEA mais ne concerne pas de la partie GPS couramment exploitée sur Arduino. Le formatage est le suivant : $IIMWV,350.0,R,000.0,N,A*3C et je souhaite donc pouvoir afficher par la suite sur un afficheur LCD les valeurs "350.0" puis "000.0". Mes recherches m'ont aiguillées vers le Parsing mais là je bloque....

1 Like

:warning:

Post mis dans la mauvaise section, ➜ déplacé vers le forum francophone général .

Merci de prendre en compte les recommandations listées dans “Les bonnes pratiques du Forum Francophone”

PS/ je le déplace

Vous avez une String ou un tableau de caractères pour votre message ?

Bonsoir F4AAG

Pour traiter ce genre de String, il y a la bibliothèque StringSplitter qui permet de récupérer les 5 premiers éléments d'après leur index.
Ainsi pour ton cas, les éléments 1 et 3.

Référence

Cordialement
jpbbricole

C’est un peu le marteau pour écraser une mouche

Le 350.0 commence à une position fixe connue, donc tres simple à extraire.

La seconde valeur commence juste après le "R," le formatage 000,0 donne à penser que les champs des valeurs sont de taille fixe avec des 0 devant si nécessaire. Si c’était le cas alors cette seconde valeur serait aussi à un endroit connu dans la chaîne

Reste plus qu’à savoir

  • si la chaîne est dans une String ou cString
  • si les champs sont de taille fixe avec des 0 en en tête ou pas
  • et éventuellement sur quel arduino cela tourne

Pour choisir la bonne approche

Bonjour J-M-L

et s'il y q toujours un R à cette place!

Avec cette bibliothèque (le marteau comme tu l'appelle) plus besoin de s'inquiéter de ça et s'il est nécessaire d'extraire d'autres paramètres, il sont déjà tout prêts.
Faire l'extraction "à la main" peut vite tourner à l'usine à gaz, surtout si les formats ne sont pas fixes.

Et puis ce marteau à le mérite d'exister et est dans la panoplie Arduino on est très souvent confronté au problème d'extraire des données avec séparateurs. Dans son format de base, la bibliothèque est limitée à 5 champs mais c'est facile d'augmenter cette limite.

Cordialement
jpbbricole

Oui, mais il semblait indiquer que c’était exactement ce format.

Oui j’aime bien le principe de parcimonie et de ne pas faire d’over-engineering en programmation sur les petits microcontrollers, surtout important si on commence à être à l’étroit en RAM ou que la fragmentation peut jouer des tours.

Si les positions sont fixes avouez que c’est aussi simple de faire la lecture en donnant le bon caractère de départ. Mais bien sûr on peut prendre le marteau :wink:

Pour ma part, sauf cas très spécial, strtok() est toujours mon choix de préférence, y compris sur ESP32. Dans le cas d'une trame NMEA, le séparateur est la virgule. Les jetons à extraire en partant de ZERO sont le N°1 et N°3. La suite coule de source :

  char s[] = "$IIMWV,350.0,R,000.0,N,A*3C";

void setup() {
  Serial.begin(115200);
  int n = 0;
  const char *token = strtok(s, ",");

  while (token != 0) {
    if (n == 1) {
      Serial.print("LAT "); Serial.println(token);
    }
    else if (n == 3) {
      Serial.print("LONG "); Serial.println(token);
    }
    token = strtok(NULL, ",");
    n++;
  }
}

void loop()
{
}

Si la chaîne est une String, je ne vois pas ce qui empêche de la remplacer par une c-string.
Recevoir une chaîne de caractère provenant de la ligne série dans une c-string n'est pas plus complexe que de la recevoir dans une String.

Oui et si les positions sont fixes, on peut faire simplement


char s[] = "$IIMWV,350.0,R,000.0,N,A*3C";

void setup() {
  Serial.begin(115200);
  double v1 = strtod (&(s[7]), nullptr);
  double v2 = strtod (&(s[15]), nullptr);
  Serial.print("v1="); Serial.println(v1,1);
  Serial.print("v2="); Serial.println(v2,1);
}

void loop() {}

C’est pour cela que je parlais du marteau.

Si la réception est dans une String, c’est pas plus compliqué:


String s = "$IIMWV,350.0,R,000.0,N,A*3C";

void setup() {
  Serial.begin(115200);
  double v1 = strtod (&(s.c_str()[7]), nullptr);
  double v2 = strtod (&(s.c_str()[15]), nullptr);
  Serial.print("v1="); Serial.println(v1,1);
  Serial.print("v2="); Serial.println(v2,1);
}

void loop() {}

En tous cas les valeurs 350.0 et 000.0 ont l'air d'avoir une position et une longueur fixe.
Ça peut fonctionner aussi.

Bonjour

C'est bien clair que si la position et la longueur des variables à extraire sont fixes , nul besoin de splitter avec la bibliothèque, la panoplie des outils String() Arduino suffisent largement comme substring() et toFloat()

Si!

Cordialement
jpbbricole

(Plutôt toFloat() sans doute)

Oui mais c’est encore le gros arsenal :wink: par rapport au simple code ci dessus.

strtod (&(s.c_str()[7]), nullptr);

Et ce n'est pas faute d'avoir déjà parlé de fragmentation mémoire :rofl: :joy:.

Surtout qu'il s'agit d'une UNO.

Conclusion habituelle :

Bonjour J-M-L

C'est corrigé, problème de lunettes :wink:

Peut-être le gros arsenal, mais certainement plus "lisible/compréhensible" par le commun des mortels dont je suis, c'est le but d'Arduino?

Cordialement
jpbbricole

Bonjour hbachetti

Bis repetita!

J'habite une région où l' on produit et on a l'habitude de boire d'excellents crus et tu veux me faire boire de la piquette...

Cordialemenzt
jpbbricole

Ça donne cela si on essaye d’être un peu compact. Un débutant passera en plus par une variable intermédiaire sans doute pour la substring.

String s = "$IIMWV,350.0,R,000.0,N,A*3C";

void setup() {
  Serial.begin(115200);
  double v1 = s.substring(7).toFloat();
  double v2 = s.substring(15).toFloat();
  Serial.print("v1="); Serial.println(v1,1);
  Serial.print("v2="); Serial.println(v2,1);
}

void loop() {} 

Pour moi ce n’est pas plus lisible mais j’ai l’historique.

Dans les 2 cas il faut avoir lu la doc de la fonction qu’on appelle.

La fonction standard strtod() (qui se lit string to double - on comprend ce que ça veut dire) qui prend un pointeur sur le début de chaîne à analyser ➜ une fonction à connaître et la notion d’adresse dans un tableau

Sinon il faut comprendre les bases de la programmation orientée objet, savoir ce qu’est une instance, comment appeler des fonctions membres et connaître deux fonctions, substring() et toFloat()

Si on est juste en mémoire, dans le premier cas on n’a pas un gros coût et il n’y a pas de besoin de mémoire intermédiaire cachée, alors que dans le second cas c’est coûteux à la fois en FLASH et en SRAM et si l’appel à substring() ne fonctionne pas car on n’a plus assez de SRAM, l’analyse va se faire au mauvais endroit et toFloat() va dire 0 sans qu’on puisse attraper l’erreur.

Ah et bien je suis heureux d'avoir autant de commentaires, c'est top !
Effectivement la structure de la chaine ne bouge pas comme la taille des valeurs. Ci-dessous une capture des trames défilant sur le port série, de où il faut maintenant extraire notre chaine....

Et bien merci pour tout ces éléments.
PS : Désolé J-M-L pour la mauvaise destination du poste.

Il suffit de regarder si la chaîne commence par $IIMWV,

Ça se fait avec startsWith() si c’est une String sinon avec strncmp() si c’est une cString.

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