Serie, parsing

Bonjour,

Je continue dans un autre registre ou j'ai pas trouvé la solution adéquate.

Je reçois une série de données sous forme de chiffre et de séparateur toute les 100ms, voir moins.
Exemple de réception : 10,50,90,0,180,0

J'ai constituer un petit code pour mettre tout ça dans un buffer:

char buffer[6];

void loop() {
  
  //Si il y a eu des données
  if(reception() > 0) {
    
    
    //String voie1, voie2, voie3, voie4, voie5, voie6;
    
    //Parser les voies
    Serial.println(buffer);
    //Serial.print("\n");
  }
  
    delay(20);
    
    
}

int reception() {
  
  //Initialisation des variables
  int sb, sInIndex = 0;
  
  //Effacer le buffer
  memset(buffer, 0, 6);
 
  //Si il y a réception d'une trame
  if(Serial1.available()) {
    
    //Boucler tant qu'il y a réception
    while(Serial1.available()) {
      
      //Charger serial bit avec les données reçus
      sb = Serial1.read(); 
      buffer[sInIndex] = sb;
      sInIndex++;
    }
    
    return sInIndex;
  } 
  
  return 0;
}

A priori le buffer se charge correctement avec les données reçus.

En revanche j'aimerais que chaque donnée soit isolée. Exemple pour la trame reçu 10,50,90,0,180,0
Voie1 = 10
Voie2 = 50
Voie3 = 90
Voie4 = 0
Voie5 = 180
Voie6 = 0

Ensuite, chaque pin (PWM) sera attacher un servo. Chaque servo ayant directement sa position contenu dans Voie1, Voie2... Voie6.

Donc il me faut parsé et quitté le côté char pour de l'int.

Merci de votre aide sur ce point.

bonjour,
sans te donner toute la solution du premier coup, cherche du coté de strtok_r

Regarde du côté de la fonction Serial.parseInt(), il me semble que c'est adapté à ce que tu veux.

En effet, je suis arrivé à un début de quelque-chose.

if(reception() > 0) {
    char *cmd, *ptr;
    cmd = strtok_r(buffer, ",", &ptr);
  
    voie1 = atoi(cmd);
    voie2 = atoi(cmd);
    voie3 = atoi(cmd);
    voie4 = atoi(cmd);
    voie5 = atoi(cmd);
    voie6 = atoi(cmd);
    
  }

Par contre, chaque voie à le même code. Ce qui semble logique vue que j'utilise toujours cmd. Il faudrait donc que je puisse trouver la deuxième valeur et ainsi de suite.

J'avance un peu.

J'ai écrit ceci:

char *cmd1, *cmd2, *cmd3, *cmd4, *cmd5, *cmd6, *ptr;
    
    cmd1 = strtok_r(buffer, ",", &ptr);
    cmd2 = strtok_r(NULL, ",", &ptr);
    cmd3 = strtok_r(NULL, ",", &ptr);
    cmd4 = strtok_r(NULL, ",", &ptr);
    cmd5 = strtok_r(NULL, ",", &ptr);
    cmd6 = strtok_r(NULL, ",", &ptr);
    
    voie1 = atoi(cmd1);
    voie2 = atoi(cmd2);
    voie3 = atoi(cmd3);
    voie4 = atoi(cmd4);
    voie5 = atoi(cmd5);
    voie6 = atoi(cmd6);

Ça semble fonctionné. Par contre, ici ça ne compile pas car la conversion char* et char est impossible :

if(reception() > 0) {
    
    char *cmd, *ptr;
    int i = 0;
    
    while((cmd = strtok_r(buffer, ",", &ptr)) != "\n") {
    
      voies[i] = cmd;
      i++;
    }
    
    voie1 = atoi(voies[0]);
    voie2 = atoi(voies[1]);
    voie3 = atoi(voies[2]);
    voie4 = atoi(voies[3]);
    voie5 = atoi(voies[4]);
    voie6 = atoi(voies[5]);

Je pense que je ne suis pas loin, mais j'ai pas trouver encore comment résoudre ce cas. Mes recherches dans l'histoire es char* to char n'a donné aucun résultat probant. Une idée ?

Vu que je ne sais pas comment tu a déclarer voies, c’est difficile de répondre

mais la solution la plus efficace est celle ci :

#define NB_VOIES            5
int voies[NB_VOIES]


int parseMessage( char *buffer)
{
   int v;
   char *ptr;
   for ( v = 0 ; v < NB_VOIES ; v++ )
   {
      char *val = strtok_r( buffer, ",", &ptr);
      if ( val == NULL )
          break;
      voies[v] = atoi( val );
      buffer = NULL;
   }

   return v;
}

Ok pour le tableau d'int. Ça me semble être ce que j'aurait du faire. Initialement j'avait déclaré char voies[32].

Par contre je pense combiné ta solution avec les interruptions. De cette façon je compte arrêter la tremblotte de mes servomoteurs.

Ceci dit je compte faire des essais et remonter le résultat de mes investigations.

Merci pour toutes ces indications.

ce que strtok_r() retourne c'est un char*
Ce que atoi() prend c'est un char*
Tu aurais du déclarer char *voies[32]; et ca aurait marché.
Mais tu aurais créé un tableau qui ne sert à rien. Autant convertir directement.

Bonjour,

Je suis pas un grand fan de la solution à base de strtok_r (qui utilise un static en interne).
Pourquoi faire compliquer quand on peu utiliser un bon vieux sscanf() :wink:

Exemple :

@skywodd

  1. strtok_r() n'utilise pas de static en interne. C'est strtok() qui le fait. strtok_r() corrige justement ce problème en remplaçant le static par le 3eme paramètre supplémentaire, ce qui rend la fonction ré-entrante (d'où le _r).

  2. strtok_r() et scanf() ont 2 buts différents.
    scanf() scanne une chaîne complète suivant un format prédéterminé.
    strtok() découpe une chaîne suivant des séparateurs et te laisse libre de l'analyse.
    scanf() marche bien avec des formats bien figés mais pose problème si le format est variable.
    Par exemple avec des chaines de type "commande,arg1,arg2,..." si le nombre d'arguments mais surtout leur type varie en fonction de la commande scanf() est moins adapté.
    Mais on peut bien sur combiner les 2 en utilisant scanf() argument par argument dans une boucle controllée par strtokr().

barbudor:

  1. strtok_r() n'utilise pas de static en interne. C'est strtok() qui le fait. strtok_r() corrige justement ce problème en remplaçant le static par le 3eme paramètre supplémentaire, ce qui rend la fonction ré-entrante (d'où le _r).

Oups, autant pour moi, je me coucherai moins bête ce soir :grin:

barbudor:
scanf() marche bien avec des formats bien figés mais pose problème si le format est variable.
Par exemple avec des chaines de type "commande,arg1,arg2,..." si le nombre d'arguments mais surtout leur type varie en fonction de la commande scanf() est moins adapté.

Il suffit de faire un format de sscanf() avec le maximum de champs possible pour une commande.
sscanf() retournant le nombre de champs extrait du buffer on peut ensuite faire un test en fonction de la commande.
Aprés il n'existe jamais une seul solution, tout dépend du type/nombres des arguments, strtok_r ou sscanf il faut choisir :grin:

mais surtout leur type varie

barbudor:
mais surtout leur type varie

Oui je suis bien d'accord que si le type varie strtok_r (+ traitement adapté de chaque champs) est la meilleur solution.
Mais (à moins que j'ai zappé un passage) Geeks travaille uniquement avec des int ?

oui, oui
c'est juste moi qui en rajoute :slight_smile: