Problème de double println

Bonjour à tous,

J'espère ne pas poster ce message dans la mauvaise catégorie, sinon je m'en excuse !

Je viens de débuter la programmation en Arduino, avec un starter kit, et mes compétences en électronique sont très limitées.

Je cherche, dans le but de réaliser un matériel de réponse à un quizz, à récupérer l'information de 4 boutons. Le but étant que, lorsque l'on appuie sur un bouton, aucun autre appui n'est comptabilisé, et lorsque l'Arduino reçoit l'information d'une nouvelle question, les boutons redeviennent "appuyables".

Voici mon montage :

Voici mon code :

//

#define bouton1 2
#define bouton2 3
#define bouton3 4
#define bouton4 5

int attenteBouton = 1;
int boutonAppuye = 0;


void setup()
{
  Serial.begin(9600);
  pinMode(bouton1, INPUT_PULLUP);
  pinMode(bouton2, INPUT_PULLUP);
  pinMode(bouton3, INPUT_PULLUP);
  pinMode(bouton4, INPUT_PULLUP);
  
}

void loop(){
  if(attenteBouton == 1 && boutonAppuye == 0){
    //Serial.println("Attente d'appui d'un bouton");
  	verifEtatBoutons();
  }
  else if (attenteBouton == 0){
    verifMessageRecu();
  }
 }

int verifEtatBoutons(){
  if (digitalRead(bouton1)==0){
    attenteBouton = 0;
    boutonAppuye = 1;
    Serial.println(boutonAppuye);
  }
  else if (digitalRead(bouton2)==0){
    attenteBouton = 0;
    boutonAppuye = 2;
    Serial.println(boutonAppuye);
  }
  else if (digitalRead(bouton3)==0){
    attenteBouton = 0;
    boutonAppuye = 3;
    Serial.println(boutonAppuye);
  }
  else if (digitalRead(bouton4)==0){
    attenteBouton = 0;
    boutonAppuye = 4;
    Serial.println(boutonAppuye);
  }
  return boutonAppuye;
}

void verifMessageRecu(){
  if(Serial.available()>0){
  while(Serial.available()>0){
    Serial.read();
    boutonAppuye=0;
    attenteBouton=1;
    }
  }
}

Quand j'appuie sur un bouton, cela m'affiche bien le bouton appuyé. Seulement voila, quand j'envoie un message à l'Arduino (pour "rouvrir" les boutons), lorsque je rappuie sur un bouton, le println s'effectue en double.
Je ne comprends pas pourquoi. J'ai essayé de regarder mon code, voir si l'instruction était donnée deux fois, mais je ne pense pas (je peux bien sur me tromper, étant débutant !).
Surtout que l'instruction est envoyée exactement au même moment, donc je ne pense pas que ce soit une question de rentrer deux fois dans la boucle...

probleme appui bouton

Auriez vous des idées ?

Merci d'avance,

Bonne fin de journée,

C'est peut-être un problème de rebond dans les boutons poussoirs. Ajoute un delay(30); dans chaque bloc if.
tu peux aussi déclarer ta fonction verifEtatBoutons en void et enlever le return puisque tu ne t'en sers pas.

Merci beaucoup pour ta réponse :slight_smile:

Pour le return sur la fonction verifEtatBoutons c'est parce que je pense en avoir l'usage plus tard, là c'est vraiment les prémices du projet :slight_smile:

Je n'avais pas pensé aux rebonds ! Merci de l'idée !
Mais s'il y avait un rebond, n'y aurait il pas un décalage ne serait ce que de quelques millisecondes ?

Si il y avait du rebond, cela n'expliquerait pas la double prise en charge. au premier appui attenteBouton passant à 0 fait que les rebonds (et les autres appuis sur les boutons) ne sont plus lus.

Je suis d'accord, mais je ne vois rien d'autre.
Peux-tu modifier ton code comme suit et nous dire ce qu'il affiche :

int verifEtatBoutons(){
  if (digitalRead(bouton1)==0){
    delay(30);
    attenteBouton = 0;
    boutonAppuye = 1;
    Serial.print("Bouton 1 : ");
    Serial.println(boutonAppuye);
  }
  else if (digitalRead(bouton2)==0){
    delay(30);
    attenteBouton = 0;
    boutonAppuye = 2;
    Serial.print("Bouton 2 : ");
    Serial.println(boutonAppuye);
  }
  else if (digitalRead(bouton3)==0){
    delay(30);
    attenteBouton = 0;
    boutonAppuye = 3;
    Serial.print("Bouton 3 : ");
    Serial.println(boutonAppuye);
  }
  else if (digitalRead(bouton4)==0){
    delay(30);
    attenteBouton = 0;
    boutonAppuye = 4;
    Serial.print("Bouton 4 : ");
    Serial.println(boutonAppuye);
  }
  return boutonAppuye;
}

Merci encore de vos réponses,

Voilà ce que me donne le moniteur série :

19:57:36.036 -> Bouton 1 : 1
19:57:49.002 -> Bouton 3 : 3
19:57:49.035 -> Bouton 3 : 3
19:57:55.923 -> Bouton 4 : 4
19:57:55.969 -> Bouton 4 : 4

Sur Tinkercad, tout fonctionne parfaitement. Donc je ne sais pas si le code est en cause...

J'ai l'impression que cela vient du buffer d'entrée. Une fois qu'un bouton a été pressé, on attend le message. Supposons que l'on envoie "Coucou". La lettre C arrive, mais le temps que les autres lettres arrivent Seriel.avilable() retourne 0 car il y a un temps entre l'arrivée des caractères (en plus avec la vitesse à 9600 bauds, un caractère va mettre environ 10ms à venir. VerifMessage a vu le premier caractères, mais les autres n'étant pas encore arrivés, la fonction se termine.

Le buffer n'est pas vide 10ms après car le reste du mot est arrivé, mais on ne fait rien car on attend un appui sur un bouton.

Quand on appuie sur un bouton, il est pris en compte et on vide d'un coup tout le buffer (si on a mis plus de 100ms pour appuyer sur le bouton, ce qui va être en principe le cas). Du coup, on affiche le numéro du bouton et comme le buffer n'est pas vide, on le vide ce qui réarme les boutons et on affiche de nouveau le numéro du bouton.

Cela se produirait si on envoie au moins deux caractères, Pour n'en envoyer qu'un seul, il ne faudrait pas mettre de retour charriot dans le message et que celui-ci ne comporte qu'une seule lettre.

Pour corriger cela, il faut mettre une attente d'au moins 10ms (le temps d'arrivée d'un caractère) dans la boucle verifMessageRecu.

Note: il me semble que le if est de trop:

void verifMessageRecu(){
  while(Serial.available()>0){
    Serial.read();
    boutonAppuye=0;
    attenteBouton=1;
    delay(20); // Attente pour que le caractère suivant ait le temps d'arriver
    }
}

devrait suffire

Tinkercad ne gère peut être pas correctement les 9600 bauds et les temps des instructions. Il est par exemple possible que le programme sur Arduino fonctionne si on passe à une vitesse de transmission plus grande. On recommande d'ailleurs de travailler à 115200 bauds. Je ne sais pas combien de temps dure Serial.available(), si c'est plus de 100µs, cela fonctionnerait, mais je ne le pense pas.

Pour le if, effectivement il était de trop, c'était une tentative désespérée de bricolage quand je ne comprenais pas pourquoi cela ne "fonctionnait pas" ! Désolé :slight_smile:

Avec cette modification du code, cela marche parfaitement !
Et surtout merci pour ces explications très claires, en tant que débutant cela me permet de mieux appréhender la chose pour éviter de reproduire ces erreurs !

Merci également pour l'explication concernant les 9600 bauds !
Sur les tutos que j'ai lu, par défaut je voyais toujours 9600 bauds donc cela me semblait suffisant, mais je vais changer mes "habitudes" ! :smiley:

Encore merci à vous :slight_smile:

Bonne soirée !

EDIT : Petite précision concernant le retour chariot, il est présent parce que je vais ensuite travailler sur Nodered pour le quizz, et au niveau du node serial, il attend le caractère \n pour afficher le message :slight_smile: Sinon effectivement un print aurait suffit !

1 Like

sinon pour bien débuter avec l'arduino, un bon point de départ c'est de lire les tutos d'eskimon - il y a parle des boutons :slight_smile:

Merci de votre réponse :slight_smile:

Oui j'ai notamment commencé par ses tutos, mais il me semble que le problème rencontré sur ce sujet n'est pas évoqué par Eskimon ! :slight_smile:

Avez-vous résolu ?

J'ai l'impression que ton code appelle deux fois une fonction.
Voici une suggestion qui pourrait vérifier l'hypothèse:
création d'une variable gloable (en tête du programme)
int rendu = 0;
puis, on transforme

Serial.print("Bouton 3 : ");

en

Serial.print("Bouton 3  " + String(rendu++) + "e fois : ");

Ainsi, tu pourras voir si tu passes là plus d'une fois ou si c'est un echo.

Au fait, c’est généralement une très mauvaise idée que d’essayer de contourner le timing d’un processus asynchrone.

La bonne façon de gérer le port série (et son petit buffer) c’est de lire souvent ce qui arrive, quand ça arrive sans bloquer le reste de la loop. Une fois que le message est arrivé c’est là qu’on le traite

Cf mon petit tuto sur le sujet

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