Microcontrôleurs et boutons poussoirs : anti-rebonds et appui long

Si les boutons poussoirs sont des composants très simples à utiliser, ils possèdent tout de même un inconvénient de taille, ils sont sujets aux rebonds, c’est à dire qu’ils ont la désagréable habitude de ne pas passer directement de leur état ouvert à leur état fermé. Pendant une durée généralement inférieure à la milliseconde, il va en effet osciller plusieurs fois entre les deux états :

Illustration signal rebonds

Allure du signal obtenu lors de l’appui sur un bouton poussoir.

Si cela ne pose pas de problème pour des applications simples, par exemple allumer une LED, ou commander un relais par le biais d’un transistor, cela en pose en revanche avec les circuits fonctionnant sur changement d’état d’un signal, ceux-ci risquant d’interpréter chaque rebond comme un appui sur le bouton. je vous propose de découvrir plusieurs méthodes pour éviter ces désagréments.

Anti-rebonds matériel : circuit RC

La solution la plus simple pour s’affranchir des problèmes de rebonds, est d’insérer le bouton dans un circuit RC :

Illustration anti-rebond RC

Anti-rebonds simple à base de circuit RC.

  1. A gauche se trouve le schéma typique pour générer un signal logique grâce à un bouton poussoir. Soit le bouton est relâché, et on retrouve la tension Vcc en sortie, à travers la résistance. Soit le bouton est appuyé, et la sortie est reliée à la masse.
  2. Au milieu, c’est un circuit RC basique. Le condensateur se charge à travers la résistance, donc lors de la mise sous tension, la tension en sortie augmente progressivement jusqu’à atteindre Vcc.
  3. En combinant les 2 montages précédents, on obtient un bouton poussoir doté d’un anti-rebonds. En effet, à la mise sous tension, le condensateur se charge à travers la résistance. Lors d’un appui sur le bouton, le condensateur se décharge instantanément à travers ce dernier ( il faut donc veiller à utiliser un condensateur de faible capacité, moins d’un µF, pour ne pas endommager le bouton ), mais ne peut pas remonter directement à Vcc, car le condensateur se charge doucement à travers la résistance. Donc, même lors des rebonds, la tension en sortie reste très proche de 0 V.

Il faut toutefois choisir l’ensemble résistance/condensateur de façon judicieuse. La constance de temps du circuit (temps que met la tension en sortie pour remonter à 2/3 de Vcc) vaut R*C où R est la valeur de la résistance et C celle du condensateur. Cette valeur doit être grande devant la durée des rebonds (qui est de quelques ms) mais suffisamment faible pour que 2 appuis consécutifs n’apparaissent pas comme un appui long. Pour répondre à ces critères, 50ms, soit 0.05s semble être une valeur tout à fait correcte.

On peut maintenant déterminer les valeurs de R et C. R doit être relativement grande ( supérieure à 1kΩ ) pour limiter le courant qui circule à travers le bouton lorsqu’il est appuyé, et C doit être suffisamment faible pour limiter les conséquences de la décharge du condensateur à travers le bouton poussoir.

Je choisi arbitrairement une valeur de C de 100 nF, car c’est une valeur courante ( on utilise souvent des condensateurs non polarisés de 100 nF placés à coté des circuits intégrés de type CMOS pour lisser la tension d’alimentation ). Il reste donc à calculer R = 0.05/C = 0.05/0.0000001 = 500kΩ. La valeur courante de résistance la plus proche est de 470kΩ. Avec cette valeur, pour une tension d’alimentation Vcc de 5v, l’intensité traversant le bouton lorsqu’il est appuyé, est proche de 10 µA, il n’y a donc aucun risque d’endommager le bouton. Il ne reste plus qu’à assembler le circuit, et le tour est joué 😉 .

Cependant, si le bouton est destiné à être connecté à un microcontrôleur, pourquoi ne pas intégrer l’anti-rebonds directement dans le programme de ce dernier ? On s’affranchirait ainsi de la place occupée par le condensateur, et éventuellement des coûts du condensateur, dans le cadre d’un circuit produit à grande échelle.

Si l’on utilise un bouton miniature, capable de supporter un très faible courant, il faut alors rajouter une résistance ( 100Ω environ ) en série avec le bouton, pour limiter le courant qui y circule lors de la décharge du condensateur.

Anti-rebonds logiciel : approche simple

La solution la plus simple, est d’attendre quelques millisecondes avant de relire l’état du bouton :

if( le bouton vient d être appuyé){
    effectuer l action nécessaire
    attendre quelques millisecondes
}

Cependant, cette solution possède plusieurs inconvénients : il faut tout d’abord suivre l’état du bouton en permanence pour détecter le moment où le bouton vient d’être appuyé ( front descendant du signal ), sans quoi l’action se répétera tant que le bouton est maintenu appuyé. De plus, on ne différencie par un appui bref d’un appui maintenu. Je vous propose donc une autre solution bien plus complète, mais également un peu plus complexe.

Anti-rebonds logiciel : approche complète avec détection d’appui long

Le code ci-dessous a été écrit en C pour un microcontrôleurs PIC avec le compilateur PICC de hi-tech, mais il est portable très facilement vers tout autre système programmable en C :

#define BUTTON_POLLING_INTERVAL 20          //intervalles de lecture du bouton, en ms
#define COUNT_DEBOUNCE 10                   //durée maximale autorisée de relâchement du bouton (en nombre d'intervalles)
#define COUNT_SHORT_PRESS 5                 //durée mini d'un appui court (en nombre d'intervalles)
#define COUNT_LONG_PRESS 50                 //durée d'un appui long (en nombre d'intervalles)

unsigned int releasedCount = 0;
unsigned totalCount = 0;

//comptage du temps d appui et anti-rebonds
while(totalCount<COUNT_LONG_PRESS){
    tempo(BUTTON_POLLING_INTERVAL);
    if(BUTTONPIN){
        releasedCount=0;
        totalCount++;
    }
    else{
        releasedCount++;
    }
    if(releasedCount>=COUNT_DEBOUNCE){
        break;
    }
}

//execution des actions apres appui
if(totalCount==COUNT_LONG_PRESS){
    //inserer ici action appui long
    while(BUTTONPIN);
}
else if(totalCount>COUNT_SHORT_PRESS){
    //inserer ici action appui bref
}
  • BUTTONPIN correspond au nom de la broche du microcontrôleur à laquelle le bouton est connecté.
  • BUTTON_POLLING_INTERVAL correspond à intervalle de temps séparant 2 lectures de l’état du bouton ( en ms ).
  • COUNT_DEBOUNCE permet l’anti-rebonds. Multiplié par BUTTON_POLLING_INTERVAL, il donne le temps que le signal du bouton doit rester à Vcc avant que le bouton soit considéré comme relâché.
  • COUNT_SHORT_PRESS multiplié par BUTTON_POLLING_INTERVAL indique la durée minimum de l’appui sur le bouton avant de déclencher l’action « appui bref ».
  • COUNT_LONG_PRESS multiplié par BUTTON_POLLING_INTERVAL indique la durée d’appui sur le bouton après laquelle l’action « appui long » est effectuée.
Explication du fonctionnement

La partie majeure du code se situe dans la boucle « while » qui lit régulièrement l’état du bouton. Le programme quitte la boucle si

  • Le bouton est lu « relâché » un nombre COUNT_DEBOUNCE de fois consécutives. On considère alors que le bouton est bien relâché.
  • Le bouton est resté appuyé un nombre COUNT_LONG_PRESS de fois. On a alors atteint la durée de l’appui long.

Une fois cette boucle quittée, le programme regarde combien de fois le bouton a été lu comme appuyé :

  • Si le bouton a été lu appuyé un nombre COUNT_LONG_PRESS de fois, qui correspond à un appui long, il effectue l’action correspondante à un appui long.
  • Sinon, si le bouton a été appuyé assez longtemps ( cette valeur est définie par COUNT_SHORT_PRESS ), il effectue l’action correspondante à un appui bref.
  • Sinon, c’est que le bouton n’a pas été appuyé, ou appuyés de façon très ponctuelle, alors le programme ne fait rien.

Après un appui long, le programme attend que le bouton soit relâché avant de continuer.

On a donc un système qui intègre un anti-rebonds, et qui permet de différencier un appui bref d’un appui maintenu, et capable d’agir en conséquence. Ayant déjà utilisé ce code, je vous conseille les valeurs suivantes pour optimiser son fonctionnement, et le confort d’utilisation du bouton :

  • BUTTON_POLLING_INTERVAL = 20
  • COUNT_DEBOUNCE = 10
  • COUNT_SHORT_PRESS = 5
  • COUNT_LONG_PRESS = 50

N’hésitez pas à me faire part de vos questions ou remarques 😉

 

6 Commentaires

1 ping

Passer au formulaire de commentaire

  1. Très bon article. Cela m’a permis de comprendre un peu plus l’électronique ^_^

    • Arnaud sur 11 septembre 2014 à 10h35
    • Répondre

    Bonjour,
    Si le bouton est en court circuit … votre programme se bloque …

  2. Bonjour,
    oui, car c’était le comportement voulu lorsque j’ai écrit ce bout de code :
    en cas d’appui long, effectuer une action, et ne rien faire pendant que le bouton reste enfoncé.
    (cf mon article sur le récepteur pour manette de xbox360)

    Pour changer ce comportement, il suffit de supprimer la ligne 27 : while(BUTTONPIN)

    A ce moment là, un appui prolongé sera interprété comme plusieurs appuis longs.

    • diallo sur 8 décembre 2016 à 19h54
    • Répondre

    Bonjour
    Tout d’abord je vous dit merci pour cet article, j’essaye de l’adapter sur µc attiny861, mais je comprend pas le total count et le releasendcount. comment les configurer ce sont des compteurs ou autres choses.

    en plus j’ai verifier si on fait un appui court plus de 5 fois sur le même bouton on passe directement dans l’action appui long et ça je comprend pas pourquoi?

    Merci d’avance

    • JEAN-MARC MANDIN sur 7 juin 2021 à 20h52
    • Répondre

    Bonjour,
    Depuis votre Code que j’ai recopié, et après avoir rajouté le Setup et la Boucle,
    Je me retrouve avec l’erreur ci après ;

    In function ‘void loop()’:
    32:12: error: ‘tempo’ was not declared in this scope
    32:12: note: suggested alternative: ‘memcpy’
    exit status 1

    Peut-être ai je mal déclaré la variable tempo ?
    Pourriez vous svp m’envoyer le code dans son intégralité.

    Je vous en remercie.

    1. Bonjour,

      Oui en effet, tempo() est à remplacer par le nom de la fonction permettant de réaliser une attente d’un certain nombre de millisecondes, dans l’environnement de développement que vous utilisez.
      Sous Arduino, il s’agit de la fonction delay() ; avec le compilateur GCC pour AVR, il s’agit de la fonction _delay_ms().

      Cela vous aide-t-il ?

      Cordialement

  1. […] Download Image More @ pila.fr […]

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.