bouton poussoir on_off

Bonjour les arduinistes

Ma modeste contribution de programmeur du dimanche après midi: un bouton poussoir "assez économique" qui allume et éteint une LED (ou modifie une variable) c'est une adaptation de code trouvé sur la toile qui ne semble pas poser de pb d'antirebond
Désolé si ça existe 1000 fois ailleurs voici le code

int button = 6; //broche où on liera la valeur renvoyée par le capteur
int led = 7; //broche où est reliée la cathode de la LED
int etat; //variable où on stockera l'état du bouton
int compteur = 0; //variable permettant de savoir si on éteint ou allume la LED

void gere_switch(){
while (etat)
{
etat = digitalRead(button);}
compteur++;
if(compteur&1) { //si compteur est impair, on allume
       digitalWrite(led,HIGH);
  }
  else { //sinon, on éteint
       digitalWrite(led,LOW);}}

void setup() {                
  pinMode(button,INPUT);//on créé une entrée : on reçoit l'état du bouton
  pinMode(led, OUTPUT);  //on créé une sortie : on donne l'état de la LED
  Serial.begin(9600);
}

void loop() {
  etat = digitalRead(button);
    if (etat){gere_switch();}
  delay(100);  //on attend pour ne pas surcharger la carte
}

bravo, c'est bien de participer.

quelques commentaires qui se veulent constructifs.

Sur la forme:

Corrigez votre post ci dessus et rajoutez lescode tags autour du code:

[code]

[color=blue]// le code ici[/color]

[/code]

.

ça doit ressembler à cela:

// le code ici

c'est mieux quand on poste sur le forum sinon des trucs bizarre peuvent apparaître

par exemple ce codex = f(8);si je ne le mets pas dans les tags devient x = f(8); <-- Non je ne veux pas de smiley à lunettes!

faites aussi ctrl-T (PC) or cmd-T (Mac) dans l'IDE avant de copier le code pour qu'il soit intenté correctement


Sur le fond:

choisissez le type des variables de manière appropriées. Par exemple la pin pour le bouton ou pour la LED sont des petites valeurs qui sont < 255 donc représentables sur un seul octet. pas la peine donc de déclarer un int pour les stocker. En plus elles ne vont jamais changer, ce sont des constantes. Autant le dire au compilateur comme cela il va faire des optimisations (en fait le compilateur n'allouera même pas la mémoire, il mettra directement la valeur dans les fonctions où la variable est utilisée, gain de place mémoire et c'est plus rapide).

const byte button = 6; //broche où on liera la valeur renvoyée par le capteur
const byte led = 7; //broche où est reliée la cathode de la LED

la gestion de l'état:

dans la boucle - qui tourne en permanence vous faites

 etat = digitalRead(button);
  if (etat) {
    gere_switch();
  }

Donc lorsque vous appelez la fonction gere_switch() la variable état doit être "vraie" (HIGH).

Quand on arrive dans gere_switch()

void gere_switch() {
  while (etat)
  {
    etat = digitalRead(button);
  }

là donc vous attendez que l'on relâche le bouton. le pb c'est que les boutons "rebondissent", il vont osciller pendant quelques milliseconds entre HIGH et LOW. Donc vous n'attendez pas vraiment qu'on relâche le bouton, vous risquez de sortir tout de suite de ce while, sur simple oscillation --> On en reparle ensuite.

Là vous incrémentez le compteur... Pourquoi prendre un compteur et faire une opération mathématique "coûteuse" (ajouter 1, regarder si le nombre est pair) alors que ce que vous voulez c'est une "bascule", un truc qui est une fois vrai, une fois faux.

Donc au lieu de int compteur = 0; //variable permettant de savoir si on éteint ou allume la LED on peut simplement prendre une variable de type booléen qui va être vraie ou fausse.

bool ledON = false; // variable donnant l'état de la LED

et donc au lieu de tester si compteur est pair on va écrire:

digitalWrite(led, ledON ? LOW : HIGH ); // operateur ternaire http://www.commentcamarche.net/contents/186-langage-c-les-structures-conditionnelles, si on était ON on passe LOW, sinon on passe HIGH
ledON = !ledON; // on inverse la valeur

Une autre façon de faire une bascule c'est avec un truc du genre:

byte bascule = 0;
...
bascule = 1-bascule; // quand bascule valait 1, ça passe à zéro (1-1) et quand bascule valait 0 on passe à 1 (1-0)

ensuite vous retournez donc dans la boucle et là vous attendez 100 ms. c'est ce qui vous "sauve" des oscillations car le bouton en 100ms a fini d'osciller et s'est stabilisé. si vous tenez encore au bout d'un dizième de seconde votre bouton cependant vous allez retourner dans gere_switch() et au moment ou vous lâchez, vous allez éteindre la LED.. Pas sûr que ce soit ce que vous vouliez... tout dépend des oscillations.


Une manière propre de tester les oscillations est d'enregistrer l'heure (millis()) de changement d'état de la lampe et de ne pas accepter de changement d'état pendant les 15 milliseconds qui suivent pas exemple. (il faut donc une variable temps et une qui mémorise l'état précédent du bouton)


Serial.begin(9600); comme vous n'utilisez pas le port série, cette ligne n'est pas nécessaire.

voilà j'espère que ça vous donne quelques idées pour améliorer votre pratique. Continuez à contribuer!

1 Like

anti rebonds :slight_smile:

CelticLord:
DIego Yourself, Comment gérer les boutons ?

anti rebonds :slight_smile:

le pb de ce tuto c'est qu'il a déclaré

// compteur de temps pour l'anti-rebond, initialisé à 0 ce qui veut
// dire qu'il n'y a pas d'anti-rebond en cours
int dateAntiRebond = 0;

Avec dateAntiRebond comme un int donc et qu'il stocke dedans millis(); qui est un unsigned long... donc le code ne va pas fonctionner bien...

C'est tres perspicace JML et tres tres bien à savoir cette erreur, j'ai juste posté ce lien pour aider mais sans entrer en profondeur je l' avoue.

Il serait peut etre sympa de signaler cette erreur à l' auteur de cet article?

Sinon je n'ai pas testé mais son code est valable en rectifiant cette erreur?

Bonsoir J_M_L,

donc plutôt que de déclarer int i dans une boucle for, on pourrait déclarer byte i si on est sur que la valeur de i ne sera jamais supérieur à 255 ?

CelticLord:
Il serait peut etre sympa de signaler cette erreur à l' auteur de cet article?

ici

J'ai parcouru rapidement globalement ça a l'air de se tenir et c'est bien de partager comme cela - il y a passé du temps.

Je changerai bien sûr aussi int tempsEcoule ,

son histoire d'interférence avec les ondes wifi etc qui peuvent créer des perturbations suffisantes pour balancer des pics à 5 V c'est un peu exagéré ,

quand il dit "J'ai choisi au hasard l'entrée numéro 8, mais cela va fonctionner avec n'importe laquelle des entrées digitales entre 0 et 13 de votre carte Arduino. " Ben faudrait mieux pas utiliser 0 et 1 car il faut des trucs sur le port série, et ça marche aussi sur les autres pins analogiques;

Le fait d'utiliser la valeur 0 dans dateAntiRebond comme indicateur est conceptuellement erroné - pas bien grave dans ce cas - mais millis() au bout d'une cinquantaine de jours repasse par zéro et donc c'est une valeur tout à fait légitime et pourtant le code l'ignorera...

Quand il dit "valeur de T=54989ms est prise au hasard" c'est un mauvais choix parce que ça ne rentre pas dans un int... (max 32767) et donc il va se retrouver avec une valeur négative..

le

// Attente de l'établissement de la connexion série
while(!Serial);

N'est pas non plus utile sur la majorité des arduinos

(ah oui il m'énerve aussi d'écrire "pallier à cela" alors qu'en bon français on doit dire "pallier cela" :slight_smile: )

donc des petits commentaires mais globalement c'est le principe

Pour laisser un commentaire il faut se connecter avec Facebook, j'ai horreur de toute cette invasion de la vie privée - j'ai pas de compte FB - donc non je n'ai pas et je ne laisserai pas de commentaire là bas.

Bonsoir Malokoxis

Oui tout fait - c'est un peu moins pénalisant car souvent on écrit

for (int i=0; i< maxnb; i++){...}

La variable prendra effectivement 2 octets mais ils seront sur la pile, donc libérés à la fin du for. Mais dans l'absolu oui ce n'est pas une mauvaise idée ... sauf quand on décrémente vers 0 ou il faut faire attention:

Par exemple si vous voulez parcourir un tableau à l'envers jusqu'au premier élément et que vous écrivez for (byte i=8; i>=0; --i) {tableau[i]=....}

Ça semble bien de premier abord mais il y'a un bug... c'est que byte est toujours positif donc quand i vaut 0 et que vous faites --i, il passe à 255 et vous allez écrire importe où dans la mémoire

Donc c'est comme tout faut réfléchir à ce qu'on fait :slight_smile:

J-M-L:
J'ai parcouru rapidement globalement ça a l'air de se tenir et c'est bien de partager comme cela - il y a passé du temps.
[...]

Merci pour tes remarques J-M-L. En effet pour le int, j'ai la mauvaise habitude de le considérer int = long, ca aurait été moins grave car ca aurait fonctionné pendant ~25 jours. Mais même ainsi ce n'était pas une bonne idée car il y a un problème de signe, la correction est en cours.
Pour "int tempsEcoule = millis() - dateAntiRebond;" c'est plus discutable : si un cycle (loop) prend plus de 30 secondes c'est qu'il y a un autre problème ailleurs. Mais uniquement pour une question de cohérence de typage je dis ok, j'accepte la modif...

Pour les interférences, ok, je "dramatise un peu", mais pour ton information, il ne faut pas un pic de +5V pour que l'entrée binaire bascule, mais un pic de +3V suffit...

Je suis désolé de "t'énerver", tel n'était pas mon objectif, tu es un très grand contributeur de ce forum, je m'en excuse...

Pour les commentaires FB c'était ou ca ou rien car je n'ai pas envie d'utiliser une BDD pour ca. J'aime que mon blog soit "léger", c'est pour cela qu'il n'y a ni javascript ni BDD. Désolé encore une fois. C'est très bien que tu ne souhaites pas exposer ta vie privée et tes chaussettes sales en postant un commentaire : seules les personnes incapables de faire attention à ce qu'elles disent ou publient ont un compte Facebook, c'est bien connu...

Le fait d'utiliser 0 n'est pas erroné, c'est un choix, même si le compteur de millis repasse à 0 tous les 2^32 millisecondes (49,7 jours), t'as donc une chance sur 2^32 / (nombre d'appuis sur le bouton en 50 jours) de tomber dessus au moment de le comparer avec la date stockée. Par ailleurs dans le code présenté, avec un objectif purement didactique, pour simplifier quelque chose qui est déjà plutôt complexe, ce cas d'overflow n'est pas du tout pris en compte. Mais ce n'est pas trop grave car au pire ca fait rater l'appui sur un bouton : il suffit de recommencer.... :smiley_cat:
Après, si tu veux du code certifiable pour l'aéronautique respectant des normes tel que la DO178B niveau A on peut en parler, mais c'est plus long, c'est plus cher et ce n'est pas pour les débutants.

Enfin, je me permets d'attendre que tu m'indiques où sont tes tutos à toi pour pouvoir les lire et apprendre suffisamment pour ne plus commettre autant d'erreurs, merci.

En résumé : Merci encore pour tes remarques, je les prends en compte, pas toutes mais presque. J'aurais cependant apprécié un peu plus de diplomatie et éventuellement préféré que tu t'adresses directement à moi, c'est bien pour cela que j'ai créé un sujet dans la section appropriée du forum... Après si ton "attaque" est en réponse à quelque chose que j'aurais dit ou fait à ton encontre j'en suis vraiment navré car encore une fois, ce n'était point mon intention (oui c'est du vieux français, en "bon français" ca veut dire : "j'ai pas voulu t'insulter").
En tout cas je suis content qu'il n'y ait qu'une seule faute d'orthographe ou de grammaire dans tout mon tuto, parce qu'il est long... merci de m'avoir rassuré en ce sens !

Restons donc diplomates et aidons nous au lieu de nous tirer dans les pattes, ne penses-tu pas que ce serait mieux ainsi ? sans rancunes ?

Z

Edit : ça y est, le tuto est corrigé...

Salut Zorro

Les affres de la communications asynchrone et anonyme... ma réponse se voulait constructive pas négative. Désolé si vous l'avez interprétée comme telle, ce n'était pas mon intention. Vous avez remarqué que j'ai commencé mon post en notant l'effort et la volonté de partage.

Si vous regardez les heures du post j'étais en train de taper ma réponse quand rjnc38 a donné le lien sur vous - je n'avais pas repéré cela sinon bien sûr je serais directement allé vous répondre et plutôt en MP; j'ai vu qu'il y avait déjà un lien sur ma réponse dans votre post donc je ne l'ai pas fait

Pour "pallier" vous avez raté le smiley et le ton humoristique - je ne me prends pas au sérieux et je ne me voulais pas moralisateur of course - j'ai été "bassiné" toute mon enfance sur cette tournure de langage :slight_smile:

Oui mon avis est discutable et vos réponses pertinentes - comme j'essayais de le dire, globalement votre contribution touchait les bons points.

Concernant ma contribution perso, je fais majoritairement des réponses aux posts et par choix de poster sur ce forum de la communauté (2 petites contrib sans ambition dans la partie tuto du forum) et modestement apporter ma pierre à l'édifice plutôt que de créer mon propre espace. Il me semble que ce sera mieux indexé, plus,visible donc plus facilement criticable par tous et que les membres du forum n'ont pas besoin de leur compte Facebook pour me répondre (aversion toute personnelle pour tout ce qui est financé par la pub, j'aime ma liberté, mais c'est un choix perso, pas un jugement de valeur sur ce que font les autres, justement chacun doit être libre).

Bref - merci pour les efforts de partage et non je ne voulais pas "vous tirer dans les pattes" - bien loin de moi cette intention, ce n'est absolument pas ma personalité. Toutes mes excuses si vous l'avez pris comme cela et j'espère que cette réponse clarifie l'intention.

ok, merci pour ces clarifications J-M-L, c'est bon de se savoir "du même coté", ma réponse était seulement de l'auto-défence, pas une attaque. Merci de l'avoir compris ainsi.
Bonne journée et à bientôt sur le forum ! :slight_smile: