Fonction strcmp sur Arduino

TP Arduino

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour à toutes et à tous !

Je suis nouvelle sur le forum, j’espère que je poste au bon endroit…

Débutante sur Arduino, je suis le TP mais je bloque depuis hier et plusieurs heures d’essais sur la fonction strcmp. Pour essayer de la comprendre, j’ai tenté, en m’aidant des indications du TP, un petit code (vois ci-dessous), mais la voie série me renvoie systématiquement "les chaînes sont différentes". J’ai essayé en tapant "requin\0" plutôt que "requin", idem. L’astuce consistant à choisir l’option "Pas de fin de ligne" ne fonctionne pas. Je pense que c’est au moins en partie lié avec le fait que Serial.read() lit caractère par caractère, car si je met un caractère unique pour motRecu tout fonctionne normalement. Ou bien je n’ai pas compris l’histoire du caractère supplémentaire et comment l’implémenter… Bref, je dois manquer quelque chose mais n’arrive pas à déterminer quoi.

Voici mon code (j’ai rajouté des Serial.println(motRecu) pour tenter de comprendre d’où vient le pb, ils ne sont pas obligatoires) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void setup()
{
  Serial.begin(9600);
}

void loop()
{
}

void serialEvent()
{
  while(Serial.available() > 0)
  {
    char motRecu[20] = {Serial.read()};

    if(strcmp(motRecu, "requin") == 0)
    {
      Serial.println(motRecu);
      Serial.println("Les chaines sont identiques");
    }
    else
    {
      Serial.println(motRecu);
      Serial.println("Les chaines sont différentes");
    }
  }
}

Pour approfondir le sujet, j’ai tenté de travailler sur le code fournit dans la correction, mais dans ce cas la voie série ne m’affiche rien du tout. Du coup j’ai carrément copié-collé le code complet pour vérifier et idem, l’affichage reste désespérément vierge, contrairement à ce qu’on voit dans la vidéo. :-( En revanche les leds fonctionnent comme attendu quand on rentre un des mots requis ou qu’on appuie sur les boutons.

Toute aide serait la bienvenue, merci d’avance pour votre aide. J’en profite aussi pour souhaiter une bonne année à toutes et tous et remercier Eskimon et Olyte pour leur excellent tutoriel !

PS : Question facultative : la voie série a chez moi du mal à gérer les caractères spéciaux comme les accents. Faut-il rajouter à mes codes quelque chose comme une indication de l’encodage à utiliser ?

Édité par sakura

+0 -0

Cette réponse a aidé l’auteur du sujet

A chaque tour de boucle, tu créer un nouveau tableau motRecu donc la première case est ce qu’il y’a sur le port série au moment.

Il faut garder le même tableau tout le long de la lecture et de la comparaison en le créant avant la boucle.

+0 -0

Cette réponse a aidé l’auteur du sujet

Hummm.

Salut déjà \o

Pour t’aider, saches que tu peux toujours allez voir les références des fonctions que tu utilises.

Par exemple strcmp : C’est en anglais malheuresement, mais de l’anglais assez simple.

Tu as pareil pour Serial.read().


Du coup, effectivement, Serial.read() ne lit qu’un caractère. C’est écrit dans sa référence.

Ensuite, il n’y a pas de raison pour que tu ne comprennes pas l’histoire du ’\0’ final. ;)

Pour terminer une chaine de caractère, l’ordinateur ne connait pas la taille de la chaine de caractère à l’avance. Et du coup, il utilise un caractère spécial. Le caractère ’\0’.

Du coup, si on oublie le caractère ’\0’, l’ordinateur va continuer à lire la chaine. Donc il ne faut jamais oublier de mettre le ’\0’ à la fin.

Le caractère ’\0’ est simplement un caractère spécial qui à pour valeur 0. Il n’a aucun sens à part signifier une fin de chaine.

Dans le TP, Eskimon utilise une fonction spéciale :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// lit un mot sur la voie série (lit jusqu'à rencontrer le caractère '\n')
void lireVoieSerie(void)
{
    // variable locale pour l'incrémentation des données du tableau
    int i = 0;

    // on lit les caractères tant qu'il y en a
    // OU si jamais le nombre de caractères lus atteint 19
    // (limite du tableau stockant le mot - 1 caractère)
    while(Serial.available() > 0 && i <= 19)
    {
        // on enregistre le caractère lu
        mot[i] = Serial.read();
        // laisse un peu de temps entre chaque accès a la mémoire
        delay(10);
        // on passe à l'indice suivant
        i++;
    }
    // on supprime le caractère '\n'
    // et on le remplace par celui de fin de chaine '\0'
    mot[i] = '\0';
}

qui lui permet de remplir le tableau mot qui fait maximum 19 caractères depuis l’entrée série. C’est quelque-chose comme ça que tu dois utiliser en combinaison avec strcmp ^^

Bon courage.

ache.one                 🦹         👾                                🦊

+0 -0
Auteur du sujet

Re-bonjour,

@ ache : J’ai bien lu les références et je crois les avoir comprises, mais je vais poursuivre mes tests avec tes indications. Question annexe : dans le code, je pense comprendre le rôle de int i, qui est une fonction qu’on retrouve souvent, mais que signifie ce "i" ? Puis-je le remplacer par qqe chose de plus explicite ?

@ Davidbrcz : Veux-tu dire qu’il faut que je déclare mon tableau en tant que variable globale ? Le résultat est encore plus bizarre…

S’agissant du code du TP : je travaille d’ordinaire sur Ubuntu mais je viens de tester le code de la correction du TP sous Windows 10. Même comportement s’agissant de la voie série qui reste vierge mais, problème supplémentaire, seule la led orange s’allume quand on rentre un mot, quel qu’il soit. Les boutons fonctionnent eux parfaitement. Du coup, je me demande s’il n’y aurait pas un conflit entre les différentes versions du logiciel Arduino et le code fourni dans le TP, qui date déjà d’il y a deux ou trois ans, si j’ai bien compris…

Merci à tous les deux pour vos indications, je vais poursuivre mes recherches. :-)

Édité par sakura

+0 -0
Auteur du sujet

Bon je crois que ça progresse, voilà où j’en suis :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int i = 0;
char motRecu[20];

void setup()
{
  Serial.begin(9600);
}


void loop()
{
}

void serialEvent()
{

  while(Serial.available() > 0 && i <=19)
  {
    motRecu[i] = {Serial.read()};
    delay(10);
    i++;
  }

  motRecu[i] = {'\0'};
  delay(10);

  if(strcmp(motRecu, "requin") == 0)
  {
    Serial.println(motRecu);
    Serial.println("Les chaines sont identiques");
  }
  else
  {
    Serial.println(motRecu);
    Serial.println("Les chaines sont différentes");
  }
}

Ne reste plus qu’à trouver le moyen de rénitialiser mon motRecu en fin de boucle, sinon les chaînes s’ajoutent les unes aux autres ce qui fait qu’elles sont toujours différentes à partir de la deuxième.

Bon si je comprends bien en tout cas, difficile de se passer du int i pour utiliser cette fonction, non ?

Un grand merci pour vos conseils ! Sur ce je vais faire une pose et je m’y remettrai plus tard. ;-)

+0 -0

Cette réponse a aidé l’auteur du sujet

Non difficile de se passer du i. Par contre, tu peux le déclarer en local dans la fonction :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void serialEvent()
{
  int i = 0; // Ici

  while(Serial.available() > 0 && i <=19)
  {
    motRecu[i] = {Serial.read()};
    delay(10);
    i++;
  }

  motRecu[i] = {'\0'};
  delay(10);

  if(strcmp(motRecu, "requin") == 0)
  {
    Serial.println(motRecu);
    Serial.println("Les chaines sont identiques");
  }
  else
  {
    Serial.println(motRecu);
    Serial.println("Les chaines sont différentes");
  }
  motRecu[0] = '\0'; // On réinitialise à la chaine sans caractère.
}

J’ai rajouté la déclaration de i et réinitialisé la chaine à la fin de la fonction. ;)
Bravo et bon repos.

Édité par ache

ache.one                 🦹         👾                                🦊

+0 -0

Salut Ge0,

L’Arduino n’est pas vraiment du C, c’est un language entre le C et le C++.

M’enfin cette syntaxe fonctionne en C++ et en C. C’est tout à fait valide et strictement équivalent à ne pas en mettre.

Le C++ n’est pas mon truc mais apparement c’est une syntaxe qui est encouragée. En C, c’est plutôt le contraire, m’enfin c’est pas vraiment génant.

ache.one                 🦹         👾                                🦊

+1 -0
Auteur du sujet

Super, ça marche ! Un grand merci ! Il va falloir sans doute encore de l’entraînement pour manier tout ça de façon fluide, mais c’est déjà un bon pas de franchi.

Pour les accolades, je les avaient rajoutées suite à des erreurs de mon compilateur annonçant qu’elles étaient nécessaires, pendant certains de mes multiples essais… Mais pas d’erreur avec la correction proposée par Ache, donc oui, les deux sont sans doute acceptables.

En revanche, mais c’est un autre sujet, la version Windows de l’IDE refuse de compiler tout ça correctement, alors qu’il n’y a pas d’erreur sous Ubuntu. :colere2:

Édité par sakura

+1 -0

En revanche, mais c’est un autre sujet, la version Windows de l’IDE refuse de compiler tout ça correctement, alors qu’il n’y a pas d’erreur sous Ubuntu. :colere2:

sakura

Je savais bien qu’il fallait que je m’éloigne d’Arduino ! :D

Plus sérieusement, je ne sais pas d’où vient le souci, mais c’est peut-être une histoire de configurations qui diffèrent.

L’Arduino n’est pas vraiment du C, c’est un language entre le C et le C++.

Non, c’est du C++. Suffit d’activer le mode verbose pour voir que c’est compilé avec avr-g++. Ca donne un côté ’nouveau langage’ à cause des ’mots clés’ (aka typedef) et l’inclusion automatique des headers liés à la lib Arduino.

Mais dès qu’on veut faire un projet un peu sérieux / structuré, il faut lacher l’IDE arduino et passer sur un véritable projet C++

+1 -0
Auteur du sujet

[edit] : Bon apparemment c’est encore mon IDE qui me joue des tours, la deuxième option marche. dommage au passage qu’on ne puisse pas supprimer un message posté par erreur.

Merci pour les infos. Je n’en suis en ce qui me concerne pas encore à programmer un arduino en C++ ! :D J’aurais une dernière question concernant la fonction strcmp : j’essaie d’introduire des ou logiques dans mes comparaisons mais je n’arrive à rien… Est-ce possible ou faut-il passer par une autre fonction ? Toujours sur la base du code donné plus haut, j’ai essayé comme suit :

1
if(strcmp(motRecu, "requin" || "meduse" || "tempete") == 0)
1
if(strcmp(motRecu, "requin") || (motRecu, "meduse") || (motRecu, "tempete") == 0)
1
if(strcmp(motRecu, "requin") == 0) || (strcmp(motRecu, "meduse") == 0) || (strcmp(motRecu, "tempete") == 0))

Pas d’erreur de compilation (sauf sur la première option), mais la voie série n’affiche plus rien quand je rentre un de ces mots…

Édité par sakura

+0 -0

@Davidbrcz: Heureux d’apprendre que la syntaxe suit le C++

@sakura: La première syntaxe n’est pas correcte.

1
("qsd" || "qsdaze")

Retourne un entier (0 ou 1), du coup, il y a de grande chance que le programme plante. Car strcmp à besoin d’une chaine de caractère.

Pour la deuxième syntaxe, c’est plus délicat. C’est valide mais équivalent à avoir écrit :

1
if(strcmp(motRecu, "requin") || "meduse" || "tempete" == 0)

Du coup, ça compile et ça passe dans le if dans tous les cas à cause de "meduse".

Bref, seule la troisième syntaxe est correcte. Il manque simplement une parenthèse ouvrante au début du if.

ache.one                 🦹         👾                                🦊

+0 -0
Auteur du sujet

Je réponds à ma question précédente, j’ai finalement trouvé la bonne syntaxe :

1
if((strcmp(motRecu, "requin") == 0) || (strcmp(motRecu, "meduse") == 0) || (strcmp(motRecu, "tempete") == 0))

Merci à tous ! (et quel casse-tête ce TP ! ;) )

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte