Les rebonds en électronique

La plupart des montages électroniques faisant intervenir une interface homme-machine, ont des claviers matricés ou simples. Plusieurs technologies existent; deux d'entre elles sont:

Les claviers à membranes:

clavier a membrane 1

et les claviers à touches:

clavier a touches 1

Une fois intégrés dans les montages, il arrive souvent qu'en phase de tests, leur mise en oeuvre laisse apparaître des dysfonctionnements qui peuvent être causés par les rebonds des touches.

rebonds dans un montage

Dans cet article on va mettre en évidence le phénomène de rebonds produit par un bouton poussoir, puis apporter quelques idées de solutions pour réduire au maximum leur influence dans un montage.

Matériel:

    • Une alimentation stabilisée +5V;
    • Un oscilloscope numérique;
    • Un Arduino Uno;
    • Un bouton poussoir du type B3F-6001 ou équivalent;
    • Une plaque à essais;
    • Un 74HC14;
    • Des résistances de : 1x10 KΩ, 1x82 KΩ, 1x18 KΩ, 7x330 Ω;
    • Un condensateur de 1μF;
    • Un afficheur 7 segments à led à cathode commune.

D'où proviennent les rebonds?

Avant de répondre à cette question, voyons d'abord la structure du bouton poussoir qui sera utilisé et son fonctionnement.

Le bouton poussoir est constitué:

  • d'un support  (1) sur lequel se trouvent les contacts et vue bouton poussoir eles 4 broches de connexions;
  • d'une coupelle flexible (2) en métal;
  • d'un plongeur (3);
  • et d'un cache métallique rigide (4).

En général les broches de connexions sont reliées deux à deux. Lorsqu'on appui sur le plongeur, celui-ci fait action sur la coupelle métallique qui se déforme et établi un contact électrique entre les deux paires de broches.

Au cours de la déformation de la coupelle, il y a un laps de temps pour lequel elle n'occupe pas sa position finale stable. Si le bouton est câblé dans un montage, il en résulte une série de pics électriques; ce sont les rebonds.

illustration bouton rebonds

Les rebonds peuvent se produire aussi lorsqu'on relâche le bouton poussoir. Leur apparition n'est pas forcément systématique.

Mise en évidence:

Le montage de test:

montage test rebonds 2

Le bouton poussoir sera relié d'un côté à la masse et de l'autre à la résistance de 10 K qui elle même est reliée au +5 V de l'alimentation (1); le point milieu entre la résistance de 10 K et le bouton poussoir ira sur une voie d'entrée de l'oscilloscope (3).

On peut observer à l'oscilloscope, ce qui se passe quand on appui sur le bouton poussoir:

capture rebonds 2

Bref un seul appui peut générer plusieurs impulsions. Cela peut être vraiment néfaste et perturber le fonctionnement d'un montage électronique.

Comment supprimer les rebonds?

Si le montage fait intervenir des microcontrôleurs, et qu'il faut éliminer les rebonds, on peut adopter soit une solution câblée, soit une solution logicielle.

Anti-rebonds câblé:

Pour le cas du bouton poussoir utilisé dans cet exemple, une solution possible consiste à le connecter à une cellule R-C, pour filtrer le rebonds, puis relier la sortie cette cellule à l'entrée d'un inverseur à trigger de Schmitt: 

antirebonds materiel 2 

D'après les calculs, on a choisi R1 = 82 KΩ, R2 = 18 KΩ, et C = 1 µF.

Le montage est alimenté en +5 V;

On appui sur le bouton poussoir: le condensateur C se décharge à travers R2. L'équation de décharge sera:

\[\mathsf{U(t)=U_0e^{-(t/R2C)}}\tag{1}\label{1}\]

U(t) : tension instantanée aux bornes du condensateur.

U0 : tension initiale aux bornes du condensateur.

D'après le schéma proposé, la broche (+) du condensateur est reliée à l'entrée de la porte inverseuse. Le but est de calculer les composants R2 et C, pour que la tension aux bornes du condensateur reste dans certaines conditions au dessus du seuil de basculement de la porte inverseuse.  Selon la documentation technique du 74HC14, ce seuil de basculement est: Uth = 1,7 V (valeur minimum).

En supposant que le condensateur est initialement chargé (U0 = 5 V).

A partir de la formule (1):

\[\mathsf{R2=\frac{-t}{C{\ell}n(U_{th}/U_0)}}\]

On peut fixer C: une valeur très petite entraîne une résistance R2 très grande, ce qui pourrait, avec le courant de fuite créer une tension résiduelle à l'entrée de la porte.

On va choisir C = 1 µF et  t = 20 ms; sachant que:U0 = 5 V, et Uth = 1,7 V..  Tous calculs faits, R2 = 18,5 KΩ; une valeur 18 KΩ ± 5% peut convenir.

On relâche le bouton poussoir: le condensateur déchargé, se charge à travers une résistance R = R1 + R2, jusqu'à la valeur finale Uf = 5 V.

L'équation de charge sera:

\[\mathsf{U(t)=U_f(1-e^{(-t/RC)})}\tag{2}\label{2}\]

Selon la documentation technique du 74HC14, le seuil de basculement Uth = 0,9 V

A partir de la formule (2):

\[\mathsf{R=\frac{-t}{C{\ell}n(1-U_{th}/U_f)}}\]

C = 1 µF. Tous calculs faits on trouve R ≈ 100 KΩ; sachant que R2 = 18 KΩ,   R1 = 82 KΩ ± 5%.

Test de la solution:

Le circuit est cablé sur plaque à essai, ensuite on l'alimente en +5 V. A l'oscilloscope on visualise à la fois la tension au borne du bouton poussoir (couleur bleu) et la tension à la sortie de la porte inverseuse (couleur jaune).

Résultat obtenu:

antirebond materiel mo

Les signaux obtenus montrent qu'il n'y a plus de rebonds lorsqu'on appui sur le bouton poussoir. Même si le choix de t = 20 ms est un peu exagéré, cela peut convenir dans certaines situations.

Anti-rebonds logiciel:

Ce sujet concernant les rebonds a été traité depuis des années; les forums ne désemplissent pas. Il suffit de rechercher dans le net, et on tombera sur des idées de solutions.

Parmi celles-ci  on trouve des algorithmes qui utilisent des compteurs pour estimer une durée fixe à partir du moment où on appui sur le bouton poussoir pour supposer qu'il n'y a plus de rebonds, et d'autres qui traduisent de façon logicielle la structure que nous avons présenté comme une solution matérielle possible; en y intégrant un trigger de Schmitt soft.

Le site arduino.cc traite ce sujet; plusieurs exemples de solutions sont proposés.

Exemple de réalisation: compteur à affichage 7 segmant à LED

Montage:

montage bp anti rebond arduino 2 

A chaque appui sur le bouton poussoir, l'afficheur est incrémenté de 1, et revient à 0 lorsqu'il atteint 9, puis le comptage recommence

On va utiliser une librairie Arduino pour résoudre ce problème. Un bouton poussoir du type B3F-6001 (fabriqué par OMRON) sera utilisé.

Exemple de programme sans anti-rebonds:

Dans ce programme tout front descendant à chaque appui sur le bouton poussoir incrémente un compteur dont le contenu sera envoyé sur un afficheur 7 segments à LEDs.

Les segments de l'afficheur sont connectés sur les ports 4, 5, 6, 7, 8, 9, 10.

#define Seg_a   4
#define Seg_b   5
#define Seg_c   6
#define Seg_d   7
#define Seg_e   8
#define Seg_f   9
#define Seg_g   10

L'initialisation de l'interface série pour le debbogage a aussi été rajoutée.

Pour afficher le chiffre 0 par exemple, seul le segment g de l'afficheur sera éteint; tous les autres seront allumés. L'ensmble des combinaisons possibles pour tous les chiffres de 0 à 9 est définit par la variable numbersTable[10][7],c'est un tableau de booléens à 10 lignes (chiffres de 0 à 9) et 7 colonnes (segments "a" à "g" de l'afficheur).

La fonction  writeNumberToDisplay(int number), permet d'afficher le contenu de la variable "number". Selon les cas le chiffre correspondant sera affiché.

La fonction setup(), initialise la liaison série et tous les ports d'entrées-sorties qui sont utilisés. Les ports connectés aux segments sont des sorties, tant dis que le port sur lequel est connecté le bouton poussoir est une entrée.

Pour finir, le programme principal, vérifie en continu si le bouton poussoir est appuyé, puis incrémente la variable "counter", ensuite la fonction writeNumberToDisplay() est appelée pour afficher le contenu de la variable "counter".  Ensuite l'instruction "Serial.println(counter)"  rend disponible le contenu de la variable "counter" sur la liaison série.

Ci-après le listing du programme; lorsqu'il est exécuté, on peut observer l'influence des rebonds, à l'aide de l'afficheur et du moniteur série Arduino:


//***********************************
// Example of undebounced push button.
// Display the number of tap to one
// digit seven segment LED display.
// Using Arduino Uno
//************************************
// Date : 2023 - 11 - 10
// By : Jt BB
//************************************
// ***********************************
// Pins and Serial baud rate
// ***********************************
#define Seg_a   4
#define Seg_b   5
#define Seg_c   6
#define Seg_d   7
#define Seg_e   8
#define Seg_f   9
#define Seg_g   10
#define DEBUG_BAUD_RATE   115200 //For debug
//************************************
// Variables
//************************************
boolean numbersTable[10][7] = 
{//Array of numbers to display
  {1,1,1,1,1,1,0}, //0 - seg a,b,c,d,e,f : on g :off
  {0,1,1,0,0,0,0}, //1 - seg b,c : on a,d,e,f,g :off
  {1,1,0,1,1,0,1}, //2
  {1,1,1,1,0,0,1}, //3
  {0,1,1,0,0,1,1}, //4
  {1,0,1,1,0,1,1}, //5
  {1,0,1,1,1,1,1}, //6
  {1,1,1,0,0,0,0}, //7
  {1,1,1,1,1,1,1}, //8
  {1,1,1,1,0,1,1}  //9
};
//
int button_pin = 11;
int button_val_last;
//**********************************
// Functions
//**********************************
// Display number
void writeNumberToDisplay(int number)
      {
         switch(number)
            {
                case 0:
                   for (int i=0; i<7; i++){//display 0
                      digitalWrite(i+4, numbersTable[0][i]);
                   }
                break;
                //
                case 1:
                   for (int i=0; i<7; i++){//display 1
                      digitalWrite(i+4, numbersTable[1][i]);
                   }
                break;
                //
                case 2:
                   for (int i=0; i<7; i++){//display 2
                      digitalWrite(i+4, numbersTable[2][i]);
                   }
                break;
                //
                case 3:
                   for (int i=0; i<7; i++){//display 3
                      digitalWrite(i+4, numbersTable[3][i]);
                   }
                break;
                //
                case 4:
                   for (int i=0; i<7; i++){//display 4
                      digitalWrite(i+4, numbersTable[4][i]);
                   }
                break;
                //
                case 5:
                   for (int i=0; i<7; i++){//display 5
                      digitalWrite(i+4, numbersTable[5][i]);
                   }
                break;
                //
                case 6:
                   for (int i=0; i<7; i++){//display 6
                      digitalWrite(i+4, numbersTable[6][i]);
                   }
                break;
                //
                case 7:
                   for (int i=0; i<7; i++){//display 7
                      digitalWrite(i+4, numbersTable[7][i]);
                   }
                break;
                //
                case 8:
                   for (int i=0; i<7; i++){//display 8
                      digitalWrite(i+4, numbersTable[8][i]);
                   }
                break;
                //
                case 9:
                   for (int i=0; i<7; i++){//display 9
                      digitalWrite(i+4, numbersTable[9][i]);
                   }
                break;
                //
                default:
                //
                break;
            }
      }
//***********************************
// Setup
//***********************************
//
void setup() {
  // pins 4 to 10 as output 
          pinMode(Seg_a, OUTPUT);
          pinMode(Seg_b, OUTPUT);
          pinMode(Seg_c, OUTPUT);
          pinMode(Seg_d, OUTPUT);
          pinMode(Seg_e, OUTPUT);
          pinMode(Seg_f, OUTPUT);
          pinMode(Seg_g, OUTPUT);
          pinMode(button_pin, INPUT_PULLUP);
  // Serial monitor
  Serial.begin(DEBUG_BAUD_RATE);
}
//***********************************
// Main
//***********************************
void loop() {
  // put your main code here, to run repeatedly:
       int button_val;
       static int counter = 0;
       button_val = digitalRead(button_pin);
       if ((button_val_last == HIGH)&&(button_val == LOW))
          {
              counter++;
              if (counter > 9){counter =0;}
              Serial.println(counter);
          }
        writeNumberToDisplay(counter);
        button_val_last = button_val;
            
}

Il faudra garder à l'esprit que les rebonds apparaissent de façon aléatoire.

Exemple de programme avec anti-rebonds:

Un algorithme spécial ne sera pas développé ici pour résoudre ce problème; on utilisera la librairie ADebouncer de Arduino. On peut retrouver celle-ci dans le gestionnaire de librairie en tapant "debouncer". Le gestionnaire propose de nombreuses librairies des contributeurs.

La librairie ADebouncer fonctionne sur le principe d'un compteur qui estime après une durée prédéfinie que le signal sur le port est stable. Pour en savoir plus sur cette librairie et comment l'utiliser, il faut se rendre sur le dépôt du contributeur; le lien est accessible directement sur l'IDE Arduino.

Le programme précédent a été légèrement modifié par l'ajout de la librairie ADebouncer.

D'abord on ajoute la librairie au programme avec la directive:

#include "ADebouncer.h"

Ensuite on crée une instance appelée "debouncer":

ADebouncer debouncer;

Celle-ci permettra d'appeler des méthodes nécessaires pour filtrer les rebonds sur le port d'entrée du bouton poussoir.

Ci-après le listing du programme:


//***********************************
// Example of push button debouncing.
// Display the number of tap to one
// digit seven segment LED display.
// Using Arduino Uno
//***********************************
// Date : 2023 - 11 - 10
// By : Jt BB
//***********************************
#include "ADebouncer.h"

#define buttonPin 11         // Define the button input pin.
#define debouncePeroid 10    // Define the debounce period in milliseconds

ADebouncer debouncer;        // Debouncer variable.


// ***********************************
// Pins and Serial baud rate
// ***********************************
#define Seg_a   4
#define Seg_b   5
#define Seg_c   6
#define Seg_d   7
#define Seg_e   8
#define Seg_f   9
#define Seg_g   10
#define DEBUG_BAUD_RATE  115200 //Serial debug

// ***********************************
// Variables
// ***********************************
boolean numbersTable[10][7] = 
{//this array give us the number to display
  {1,1,1,1,1,1,0}, //0 - seg a,b,c,d,e,f : on g :off
  {0,1,1,0,0,0,0}, //1 - seg b,c : on a,d,e,f,g :off
  {1,1,0,1,1,0,1}, //2
  {1,1,1,1,0,0,1}, //3
  {0,1,1,0,0,1,1}, //4
  {1,0,1,1,0,1,1}, //5
  {1,0,1,1,1,1,1}, //6
  {1,1,1,0,0,0,0}, //7
  {1,1,1,1,1,1,1}, //8
  {1,1,1,1,0,1,1}  //9
};

//************************************
// Functions
//************************************

// Display number
void writeNumberToDisplay(int number)
      {
         switch(number)
            {
                case 0:
                   for (int i=0; i<7; i++){//display 0
                      digitalWrite(i+4, numbersTable[0][i]);
                   }
                break;
                //
                case 1:
                   for (int i=0; i<7; i++){//display 1
                      digitalWrite(i+4, numbersTable[1][i]);
                   }
                break;
                //
                case 2:
                   for (int i=0; i<7; i++){//display 2
                      digitalWrite(i+4, numbersTable[2][i]);
                   }
                break;
                //
                case 3:
                   for (int i=0; i<7; i++){//display 3
                      digitalWrite(i+4, numbersTable[3][i]);
                   }
                break;
                //
                case 4:
                   for (int i=0; i<7; i++){//display 4
                      digitalWrite(i+4, numbersTable[4][i]);
                   }
                break;
                //
                case 5:
                   for (int i=0; i<7; i++){//display 5
                      digitalWrite(i+4, numbersTable[5][i]);
                   }
                break;
                //
                case 6:
                   for (int i=0; i<7; i++){//display 6
                      digitalWrite(i+4, numbersTable[6][i]);
                   }
                break;
                //
                case 7:
                   for (int i=0; i<7; i++){//display 7
                      digitalWrite(i+4, numbersTable[7][i]);
                   }
                break;
                //
                case 8:
                   for (int i=0; i<7; i++){//display 8
                      digitalWrite(i+4, numbersTable[8][i]);
                   }
                break;
                //
                case 9:
                   for (int i=0; i<7; i++){//display 9
                      digitalWrite(i+4, numbersTable[9][i]);
                   }
                break;
                //
                default:
                //
                break;
            }
      }
// ************************************************
// Setup 
// ************************************************

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);               // Set the button mode as input pullup.  
  // I/O pins 4 to 10 are output 
          pinMode(Seg_a, OUTPUT);
          pinMode(Seg_b, OUTPUT);
          pinMode(Seg_c, OUTPUT);
          pinMode(Seg_d, OUTPUT);
          pinMode(Seg_e, OUTPUT);
          pinMode(Seg_f, OUTPUT);
          pinMode(Seg_g, OUTPUT);
  //
  debouncer.mode(DELAYED, debouncePeroid, HIGH);  // Set the debounce mode as delayed mode and debounce period as 10 ms, with the initial output in a HIGH state.
  Serial.begin(DEBUG_BAUD_RATE);
}

void loop() {
  static int counter = 0;
  debouncer.debounce(digitalRead(buttonPin));  // Save the debounced of the button state.
  if (debouncer.falling())
  {
    counter++;
    if (counter > 9){counter =0;}
    Serial.println(counter);
  }
  writeNumberToDisplay(counter);
     
}

 

Lorsqu'on exécute ce programme, le fonctionnement du montage est nettement amélioré. Le résumé de l'article est proposé dans cette vidéo.

 

 

Conclusions:

Les boutons poussoirs qu'ils soient à touches ou à membranes peuvent produire des rebonds; pas seleument; les contacts d'un relais ou d'un capteur de fin de course aussi peuvent en produire.

Ce sujet toujours d'actualité date de longtemps. Des solutions existent pour réduire voire supprimer les rebonds, les choix dépendent des exigences, et de l'environnement dans lequel le montage va évoluer.

 

JtBB

Ce site web utilise des cookies

Certains d’entre eux sont essentiels pour son fonctionnement et d’autres nous aident à améliorer l’expérience utilisateur (cookies traceurs). Vous pouvez décider vous-même si vous autorisez ou non ces cookies. Merci de noter que, si vous les rejetez, certaines fonctionnalités du site pourront être défaillantes.