Je suis la tuto de zes de savoir, lors du TP "baignade interdite" mon code sur le simulateur tinkercad fonctionne parfaitement bien mais pas sur arduino. Le comparateur de mot lu sur la voie série ne renvoie pas une similitude des mots comparés alors qu'ils sont parfaitement identiques.
Exemple : if(strcmp(motSerie, "vague") == 0)
{ Serial.println("les mots sont identiques");}
else
{ Serial.println("les mots ne sont pas identiques");}
Alors que motSerie est bien "vague" il me retourne non identique?? alors que le même code dans tinkercad fonctionne parfaitement. Quelqu'un peut-il m'éclairer sur ce petit problème, je précise que je suis débutant dans cette technologie.
Post mis dans la mauvaise section, on parle anglais dans les forums généraux. ➜ déplacé vers le forum francophone.
Merci de prendre en compte les recommandations listées dans "Les bonnes pratiques du Forum Francophone”
Bonjour,
Met code en entier, en particulier la définition de motSerie
Bonjour kamill, voici le code en entier, merci d'avance pour le temps que tu y consacreras
#define VERT 0
#define ORANGE 1
#define ROUGE 2
int etatLed = 0; // stock l'état led 0,1 ou 2 suivant la lecture
// du danger sur la voie série.
char motSerie[20];//tableau de 20 caractères MAX pour stocker le
//mot lu sur la voie série.
const int btn_alarme = 2;//le bouton d'alarme est sur la broche 2
const int btn_raz = 3;// le bouton de reset alarme sur la broche 3
const int led_tab[3] = {11,12,13};// tableau de brochage des 3 Leds
void setup()
{
Serial.begin(9600);
for(int j = 0;j < 3;j++)
{
pinMode(led_tab[j],OUTPUT);
digitalWrite(led_tab[j],HIGH);
}
pinMode(btn_alarme,INPUT);
pinMode(btn_raz,INPUT);
}
void loop()
{
// On teste le bouton alarme
if(digitalRead(btn_alarme) == LOW)
{
gestion_alarme(); // oui il y a une alarme, alors on appelle
// la fonction gestion_alarme()
}
//Maintenant on va tester la voie serie
if(Serial.available() > 0)
{
lire_voie_serie();
etatLed = comparateur_mot(motSerie);
}
gestion_affichage(etatLed);
}
void gestion_alarme(void)
{
long tempo = millis();
bool clignotant = false;
gestion_affichage(-1);
// Faire clignoter la led rouge tant que le bouton RAZ
// n'a pas été appuyé.
while(digitalRead(btn_raz) != LOW)
{
if((millis() - tempo) > 250)
{
clignotant = !clignotant;
digitalWrite(led_tab[ROUGE],clignotant);
tempo = millis();
}
}
}
void gestion_affichage(int numled)
{
for(int x = 0;x < 3; x++)
{
digitalWrite(led_tab[x],HIGH); // on éteind les 3 led
}
if(numled != -1)
{
digitalWrite(led_tab[numled], LOW);
}
}
void lire_voie_serie(void)// cette fonction ne renvoie rien et
// ne recois rien.
{
int i = 0;// variable d'incrémentation du tableau de données
while(Serial.available() > 0 && i <=19)
{
motSerie[i] = Serial.read();
delay(10);
i++;
}
motSerie[i] = '\0';
}
int comparateur_mot(char motSerie[])
{
if(strcmp(motSerie,"surveillant") == 0)
{
return VERT;
}
if(strcmp(motSerie,"calme") == 0)
{
return VERT;
}
if(strcmp(motSerie,"vague") == 0)
{
return ORANGE;
}
if(strcmp(motSerie,"meduse") == 0)
{
return ROUGE;
}
if(strcmp(motSerie,"tempete") == 0)
{
return ROUGE;
}
if(strcmp(motSerie,"requin") == 0)
{
return ROUGE;
}
return ORANGE;
}
Il n'y a pas de raison pour que la comparaison ne fonctionne pas en réel.
Par contre je vois une raison potentielle pour que la réception ne fonctionne. A 9600 bauds il faut environ 10ms pour transmettre un caractère, or dans ta boucle de réception tu as un délai de 10ms, il se peut donc que si l'espace entre deux caractères est un chouia supérieur à 10ms tu considères que la transmission est finie alors qu'elle ne l'est pas.
Il se peut aussi que ton terminal soit configuré avec cr lf et ta chaine va contenir ces caractères à la fin.
- vérifie que ton terminal n'envoie pas cr lf
- configure ta liaison à 115200 bds
- affiche la chaine reçue à la fin de
lire_voie_serie(void)
pour vérification
Remarque: il serait mieux d'envoyer un terminateur lf avec le terminal et de lire le message avec readByteUntil()
readByteUntil() : +1 avec kamill
A mon avis la comparaison ne fonctionne pas car la chaîne contient un caractère '\n', ou '\r\n', en fonction de la configuration du moniteur série.
Merci, je check tout cela et je te tiens au courant des résultat, bon dimanche. Dany
Si le mot est entrée à la main dans un terminal qui envoie caractère par caractère il peut se passer plusieurs centaines de ms entre 2 caractères.
Il est nettement plus sûr de définir un terminateur de chaîne et de remplir le tampon de réception jusqu'à la réception de ce terminateur (ou à la saturation du tampon).
Merci pour ta réponse fdufnews , je check cette solution aussi. Dany
Si le moniteur de l'IDE ARDUINO est utilisé il envoie la ligne saisie lorsque l'on appuie sur RETURN ou clique sur Envoyer. Il n'y a pas de temps inter-caractère.
Par contre s'il s'agit d'un vrai terminal, les caractères sont envoyés à chaque appui touche.
J'utilise en effet le terminal série de l'IDE ARDUINO 1.8.19, quelle est la syntaxe de readByteUntil(). Si un caractère '\n' devait exister il serait supprimer à la sortie du while par la ligne de code
motSerie[i] = '\0';
Non ?
Non. Ça marque simplement la fin de chaine (ce qui est une bonne chose), mais si le \n est dans la chaine ça ne le supprimera pas.
Pour supprimer \n
char *p;
if ((p=strchr(motSerie,'\n'))!=NULL)
*p=0;
idem pour \r
Un petit exemple :
Le terminal série doit être réglé sur "Nouvelle ligne", sinon, s'il est réglé sur "les deux, NL et CR", un '\r' subsistera.
Merci à kamill et hbachetti pour vos réponses et proposition, je suis vraiment content de voir le dynamisme de ce forum. Un grand merci à vous tous, je vais maintenant faire un petit code tout simple et tester les différentes solutions. Bon dimanche à vous. Dany
Bonjour data_13
Avec le terminal série de l'IDE, comme la majorité des autres émetteurs de chaînes de caractères, les caractères sont envoyés en une salve avec la touche enter ou le bouton envoyer. De ce fait tu peux ignorer les caractères de terminaison de transmission comme \n et \r. Pour ce faire il faut travailler avec le timout du port série en l'initialisant ainsi:
Serial.begin(115200);
Serial.setTimeout(50); // Pour fin des commandes depuis le moniteur
à la réception avec Serial.readString(), il suffit de supprimer les caractères indésirables ainsi:
cmdTexte.replace("\n", "");
cmdTexte.replace("\r", "");
Le code complet:
bool cmdNouvelleRecue = false; // Si une nouvelle commande a été reçue
String cmdTexte = ""; // Texte de la commande
void setup()
{
Serial.begin(115200);
Serial.setTimeout(50); // Pour fin des commandes depuis le moniteur
}
void loop()
{
//--------------------------------- Ecoute du port serie
serialRead();
if (cmdNouvelleRecue) // Si une nouvelle commande depuis le moniteur
{
Serial.println("Commande recue : " + cmdTexte);
cmdTexte = "";
cmdNouvelleRecue = false;
}
}
/*-----------------------------------------------------------------------
Réception de commandes depuis le moniteur
'*------------------------------------------------------------------------
*/
void serialRead()
{
if (Serial.available())
{
cmdTexte = Serial.readString();
cmdTexte.replace("\n", "");
cmdTexte.replace("\r", "");
cmdNouvelleRecue = true;
}
}
Cordialement
jpbbricole
Merci à à toi jpbbricole, mais là j'ai besoin d'un peu de temps pour digérer le code que tu m'as donné, comme je l'ai déjà dit je suis débutant en arduino, j'ai une petite formation en c++, mais les fonctions que tu me donnes je dois les étudier. Un grand merci quand même. Bonne soirée, Dany
Il me semble utile de rappeler que data_13 utilise strcmp() dans son logiciel, et donc des C-strings, et donc qu'il maîtrise le sujet, à quelques détails près. Utiliser readString() au lieu de readByteUntil() implique d'utiliser des Strings (allocation dynamique) au lieu des C-strings (allocation statique ou locale), et il y a un risque, la fragmentation mémoire, à moins de pré-dimensionner la String (voir la méthode String::reserve()).
Merci à tous pour votre aide et la solution a été donnée par kamill, je donne la fonction "void lire_voie_serie(void).
void lire_voie_serie(void)// cette fonction ne renvoie rien et
// ne recois rien.
{
int i = 0;// variable d'incrémentation du tableau de données
while(Serial.available() > 0 && i <=19)
{
char *p;
motSerie[i] = Serial.read();
if((p=strchr(motSerie,'\n')) != NULL)
*p=0;
if((p=strchr(motSerie,'\r')) != NULL)
*p=0;
delay(10);
i++;
}
motSerie[i] = '\0';
}
Maintenant que vous avez trouvé la solution, comment je clôture ce sujet SVP ? oui je pousse un peu. Cordialement Dany
Pour kamill,
J'ai appliqué ta solution sans bien comprendre ton algorithme, je crois que tu fais appelle à un pointeur char et à la fonction strchr(), que je n'ai pas encore vu, mais je vais m'y mettre sans délai. Encore merci à toi. Dany
Tu n'as pas besoin de faire la recherche de \n \r à chaque caractère reçu. Il suffit de la faire à la fin de la réception
void lire_voie_serie(void)// cette fonction ne renvoie rien et
// ne recois rien.
{
int i = 0;// variable d'incrémentation du tableau de données
while(Serial.available() > 0 && i <19)
{
motSerie[i] = Serial.read();
delay(10);
i++;
}
motSerie[i] = '\0';
char *p;
if ((p=strchr(motSerie,'\n'))!=NULL)
*p=0;
if ((p=strchr(motSerie,'\r'))!=NULL)
*p=0;
}
Il y a une petite erreur dans le test de i dans le while. C'est i<19 et non i<=19.
En effet avec i<19 tu vas recevoir les caractères 0 à 18, ce qui fait 19 caractères plus le \0 que tu rajoute ça fait 20 et c'est ok.
Avec i<=19 tu reçois 20 caractères plus le \0 de fin -> 21. Tu débordes du tableau.
En fait il vaudrait mieux écrire
while(Serial.available() > 0 && i <sizeof motSerie-1)
, comme ça si tu changes la taille de motSerie c'est automatiquement pris en compte.