Bouton Poussoir Arduino : Débounce, Pull-up et Interruptions en Tunisie
Maîtrisez le bouton poussoir Arduino : pull-up, debounce avec millis(), Bounce2, interruptions, appui long et double-clic. 5 patterns prêts à l'emploi.
En 1947, dans les laboratoires Bell, William Shockley et son équipe inventent le transistor. Soixante-dix ans plus tard, un étudiant ISET passe trois nuits à comprendre pourquoi sa LED s’allume “deux fois” quand il appuie une seule fois sur son bouton. Le coupable n’est ni le transistor, ni Arduino, ni le code — c’est un phénomène mécanique vieux de cent ans que les ingénieurs appellent rebond de contact. Quand deux lamelles métalliques se touchent, elles oscillent pendant 1 à 15 ms avant de se stabiliser. Pour un humain, c’est invisible. Pour un Arduino à 16 MHz, ce sont des centaines d’événements ON/OFF interprétés comme autant d’appuis. Apprendre à lire correctement un bouton poussoir, c’est apprendre la moitié de l’électronique embarquée. Ce guide vous donne les clés.
- 1. Les types de boutons et leurs usages
- 2. Pull-up vs pull-down : la base à maîtriser
- 3. INPUT_PULLUP : le secret d’Arduino
- 4. Le problème des rebonds illustré
- 5. Debounce logiciel avec millis()
- 6. La librairie Bounce2
- 7. Interruptions matérielles INT0/INT1
- 8. Appui long et double-clic
- 9. L’encodeur rotatif KY-040
- 10. 5 patterns de code réutilisables
- FAQ
1. Les types de boutons et leurs usages
Tous les “boutons” ne se valent pas. Choisir le mauvais type, c’est garantir trois soirées de débogage stérile. Voici la typologie que nous utilisons chez Didactico :
| Type | Comportement | Usage typique | Prix Tunisie |
|---|---|---|---|
| Tactile 6×6 mm | Momentané (appuyé = ON) | Breadboard, prototypes | 0,3 – 0,5 DT |
| Poussoir 12 mm panneau | Momentané, robuste | Boîtier de projet final | 1,5 – 3 DT |
| TTP223 capacitif | Détection tactile sans contact | Interface premium, derrière acrylique | 2 – 4 DT |
| Toggle SPDT | Bistable (ON ou OFF maintenu) | Interrupteur d’alimentation | 1 – 2 DT |
| Bouton arcade 30 mm | Momentané grande course | Borne d’arcade, jeux | 5 – 12 DT |
| Reed switch magnétique | ON par proximité aimant | Alarme porte, compteur tours | 1 – 3 DT |
Pour 90 % des projets, vous utiliserez un bouton tactile 6×6 mm pour le prototype, puis un poussoir 12 mm pour la version finale en boîtier.
2. Pull-up vs pull-down : la base à maîtriser
Un bouton seul ne suffit pas. Quand il est ouvert (non pressé), la broche d’entrée Arduino n’est connectée à rien : elle “flotte” et capte le bruit ambient, donnant des LOW et HIGH aléatoires. Il faut imposer un état par défaut grâce à une résistance.
Pull-down (état par défaut = LOW)
5V
|
/ Bouton
|
+------ Arduino pin D2
|
[R 10k] <-- pull-down
|
GND
Au repos : la résistance tire la broche à GND, donc digitalRead() = LOW. Appui : le 5V est connecté à la broche, digitalRead() = HIGH.
Pull-up (état par défaut = HIGH)
5V
|
[R 10k] <-- pull-up
|
+------ Arduino pin D2
|
/ Bouton
|
GND
Au repos : la résistance tire la broche à 5V, digitalRead() = HIGH. Appui : la broche est court-circuitée à GND, digitalRead() = LOW.
99 % des projets professionnels utilisent le pull-up. Pourquoi ? Parce qu’en cas de fil coupé, la broche reste à HIGH (état “sûr” = bouton non pressé), évitant les fausses détections. Adoptez ce réflexe dès le premier jour.
3. INPUT_PULLUP : le secret d’Arduino
Tous les microcontrôleurs ATmega328P (UNO, Nano), ESP32, ESP8266, STM32 intègrent des résistances de pull-up internes d’environ 20-50 kΩ activables par logiciel. Plus besoin de soudure ! Un simple :
pinMode(2, INPUT_PULLUP);
active le pull-up interne. Le bouton se câble alors entre la broche D2 et GND, point final. Voici le code minimal :
const byte BOUTON = 2;
const byte LED = 13;
void setup() {
pinMode(BOUTON, INPUT_PULLUP);
pinMode(LED, OUTPUT);
}
void loop() {
// INPUT_PULLUP : appuye = LOW, relache = HIGH
if (digitalRead(BOUTON) == LOW) {
digitalWrite(LED, HIGH);
} else {
digitalWrite(LED, LOW);
}
}
Simple, élégant, fonctionne immédiatement. Mais ce code n’est pas robuste : il ne gère pas les rebonds. On y vient.
4. Le problème des rebonds illustré
Quand vous appuyez sur un bouton, voici ce que voit réellement l’Arduino sur l’oscilloscope :
Tension Appui Relache
HIGH ----+ +-+ +--+ +-+ +----
| | | | | | | |
| | | | | STABLE | | |
LOW +-+-+ +-+-+ +--------------+-+------+
<~~~ 5 a 15 ms rebonds ~~~>
Cinq à quinze millisecondes de rebonds chaotiques. Si votre loop() tourne à 50 000 itérations/seconde (typique sur Arduino UNO), elle voit chaque rebond comme un appui distinct. Résultat : votre compteur incrémente de 7 au lieu de 1, votre menu saute trois lignes, votre relais claque sept fois.
5. Debounce logiciel avec millis()
Le principe est simple : on ignore tout changement d’état qui survient moins de 30 à 50 ms après le précédent. Voici un debounce robuste sans aucune librairie :
const byte BOUTON = 2;
const byte LED = 13;
const unsigned long DEBOUNCE_MS = 50;
byte etatLed = LOW;
byte dernierEtatLu = HIGH;
byte etatStable = HIGH;
unsigned long dernierChangement = 0;
void setup() {
pinMode(BOUTON, INPUT_PULLUP);
pinMode(LED, OUTPUT);
}
void loop() {
byte lecture = digitalRead(BOUTON);
// Si l'etat change, on memorise l'instant
if (lecture != dernierEtatLu) {
dernierChangement = millis();
}
// Si l'etat est stable depuis assez longtemps
if (millis() - dernierChangement > DEBOUNCE_MS) {
if (lecture != etatStable) {
etatStable = lecture;
// On agit uniquement sur front descendant (appui)
if (etatStable == LOW) {
etatLed = !etatLed;
digitalWrite(LED, etatLed);
}
}
}
dernierEtatLu = lecture;
}
Ce pattern est l’un des plus utilisés en embarqué. Apprenez-le par cœur : il marche identiquement pour 1 ou pour 50 boutons, sur Arduino comme sur ESP32.
6. La librairie Bounce2 — la solution propre
Pour ne pas réécrire ce code à chaque projet, Thomas Fredericks a créé Bounce2, devenue le standard. Installation : Outils → Gérer les bibliothèques → “Bounce2”.
#include <Bounce2.h>
Bounce bouton = Bounce();
const byte LED = 13;
bool etatLed = false;
void setup() {
bouton.attach(2, INPUT_PULLUP);
bouton.interval(25); // 25 ms de debounce
pinMode(LED, OUTPUT);
}
void loop() {
bouton.update();
if (bouton.fell()) { // front descendant = appui
etatLed = !etatLed;
digitalWrite(LED, etatLed);
}
}
Bounce2 expose plusieurs méthodes très pratiques : fell() (front descendant), rose() (front montant), read() (état stable), currentDuration() (depuis combien de temps dans cet état). Pour 5 boutons, vous créez simplement 5 objets Bounce. Aucune complexité.
Boutons, résistances, breadboard
Pack tactiles 6×6 mm (lot de 25), résistances 10kΩ, fils Dupont. Tout le nécessaire pour vos prototypes Arduino. En stock à Sfax, livré sous 24-48h en Tunisie.
7. Interruptions matérielles INT0/INT1
Le polling (digitalRead() dans la loop) a un défaut : si votre loop met 200 ms à s’exécuter, vous pouvez rater un appui bref. La solution radicale : les interruptions matérielles. Le processeur arrête immédiatement ce qu’il fait pour exécuter une fonction spéciale (ISR — Interrupt Service Routine).
Sur Arduino UNO, deux broches supportent les interruptions externes : D2 (INT0) et D3 (INT1). Sur Mega : D2, D3, D18, D19, D20, D21. Sur ESP32 : presque toutes les broches.
const byte BOUTON = 2; // INT0
const byte LED = 13;
volatile bool changement = false;
volatile unsigned long dernierTick = 0;
void ISR_bouton() {
// Debounce dans l'ISR (45 ms)
unsigned long t = millis();
if (t - dernierTick > 45) {
changement = true;
dernierTick = t;
}
}
void setup() {
pinMode(BOUTON, INPUT_PULLUP);
pinMode(LED, OUTPUT);
attachInterrupt(digitalPinToInterrupt(BOUTON), ISR_bouton, FALLING);
}
void loop() {
if (changement) {
changement = false;
digitalWrite(LED, !digitalRead(LED));
}
// ICI tout votre code applicatif, meme long
}
1. Toute variable partagée ISR/loop doit être déclarée volatile. 2. Une ISR doit être la plus courte possible : pas de Serial.print(), pas de delay(), pas de calculs flottants lourds. 3. Mettre un drapeau (flag = true) et traiter dans la loop, pas dans l’ISR. 4. millis() fonctionne dans une ISR mais delay() bloque tout.
8. Appui long et double-clic
Vos utilisateurs aiment les interactions riches : appui court = action A, appui long = action B, double-clic = action C. Voici comment l’implémenter proprement :
#include <Bounce2.h>
Bounce btn = Bounce();
const unsigned long SEUIL_LONG = 1000; // 1 s
const unsigned long FENETRE_DOUBLE = 350; // 350 ms
unsigned long tDebutAppui = 0;
unsigned long tDernierClic = 0;
bool attenteSecondClic = false;
bool appuiLongDetecte = false;
void setup() {
Serial.begin(115200);
btn.attach(2, INPUT_PULLUP);
btn.interval(25);
}
void loop() {
btn.update();
if (btn.fell()) { // debut appui
tDebutAppui = millis();
appuiLongDetecte = false;
}
// Detection appui long pendant que le bouton est tenu
if (btn.read() == LOW && !appuiLongDetecte &&
(millis() - tDebutAppui > SEUIL_LONG)) {
Serial.println("APPUI LONG");
appuiLongDetecte = true;
}
if (btn.rose()) { // relachement
if (appuiLongDetecte) return; // deja traite
if (attenteSecondClic && (millis() - tDernierClic < FENETRE_DOUBLE)) {
Serial.println("DOUBLE CLIC");
attenteSecondClic = false;
} else {
attenteSecondClic = true;
tDernierClic = millis();
}
}
// Si la fenetre double-clic expire, c'etait un simple clic
if (attenteSecondClic && (millis() - tDernierClic > FENETRE_DOUBLE)) {
Serial.println("SIMPLE CLIC");
attenteSecondClic = false;
}
}
Pour plus de simplicité, regardez la librairie OneButton qui implémente nativement attachClick(), attachDoubleClick(), attachLongPressStart() — idéale pour les interfaces multi-boutons.
9. L’encodeur rotatif KY-040 (introduction)
Quand un seul bouton ne suffit plus, l’encodeur rotatif est la suite logique : rotation gauche/droite + bouton intégré. Le KY-040 est l’un des plus répandus en Tunisie.
Brochage : CLK, DT (les deux signaux quadrature), SW (bouton-poussoir intégré), +, GND. Lecture quadrature simplifiée :
const byte CLK = 2;
const byte DT = 3;
const byte SW = 4;
volatile int compteur = 0;
volatile byte ancien = 0;
void setup() {
Serial.begin(115200);
pinMode(CLK, INPUT_PULLUP);
pinMode(DT, INPUT_PULLUP);
pinMode(SW, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(CLK), lireEncodeur, CHANGE);
}
void lireEncodeur() {
byte clk = digitalRead(CLK);
byte dt = digitalRead(DT);
if (clk == dt) compteur++;
else compteur--;
}
void loop() {
static int dernier = 0;
if (compteur != dernier) {
Serial.println(compteur);
dernier = compteur;
}
}
Pour un projet propre, utilisez la librairie RotaryEncoder de Matthias Hertel qui gère parfaitement les rebonds et la quadrature.
10. 5 patterns de code réutilisables
Pattern A — Bouton ON/OFF (toggle)
if (btn.fell()) etat = !etat;
digitalWrite(LED, etat);
Pattern B — Bouton momentané (relais tant qu’appuyé)
btn.update();
digitalWrite(RELAIS, btn.read() == LOW ? HIGH : LOW);
Pattern C — Compteur incrémental
if (btn.fell()) {
compteur++;
Serial.println(compteur);
}
Pattern D — Sélecteur de mode cyclique (5 modes)
if (btn.fell()) {
mode = (mode + 1) % 5;
appliquerMode(mode);
}
Pattern E — Boot mode (appui maintenu au démarrage)
void setup() {
pinMode(BOUTON, INPUT_PULLUP);
delay(50); // stabilisation
if (digitalRead(BOUTON) == LOW) {
Serial.println("Mode configuration");
modeConfig = true;
}
}
Arduino UNO R3 + Kit Découverte
Le combo idéal pour les étudiants ENIT, INSAT, ISBS, ISET et ESPRIT. Inclut Arduino UNO authentique, breadboard, LEDs, boutons et résistances pour démarrer.
FAQ — Bouton poussoir Arduino
Faut-il toujours une résistance pull-up externe avec Arduino ?
Non. Tous les Arduino (UNO, Nano, Mega, Leonardo) possèdent des résistances de pull-up internes activables avec pinMode(pin, INPUT_PULLUP). Vous gagnez une résistance et un câble. La résistance externe n’est nécessaire que si vous avez un câble très long (> 50 cm) ou un environnement très bruyant (proximité moteurs), où il faut une valeur plus faible (1-4,7 kΩ).
Quelle est la différence entre digitalRead() et l’interruption ?
digitalRead() dans la loop (polling) vérifie l’état à chaque tour : si la loop est lente, vous ratez les appuis brefs. L’interruption matérielle (attachInterrupt) déclenche immédiatement une fonction dès que la broche change, même si le processeur est occupé. Utilisez les interruptions pour les événements critiques (arrêt d’urgence, capteur rapide) et le polling pour les boutons utilisateur standards.
Combien de boutons puis-je connecter sur un Arduino UNO ?
L’Arduino UNO a 14 broches numériques (D0-D13) + 6 broches analogiques utilisables en numérique (A0-A5), soit 20 boutons maximum. Pour plus, utilisez un multiplexeur 74HC4051 (8 entrées sur 3 broches), un PCF8574 (8 entrées en I2C, chaînable jusqu’à 64), ou une matrice clavier 4×4 (16 boutons sur 8 broches).
Pourquoi ma LED clignote au lieu de rester allumée ?
Vous lisez probablement le bouton sans debounce et utilisez !etatLed dans la loop : à chaque rebond, la LED change d’état des dizaines de fois pendant l’appui. Solution : utilisez la librairie Bounce2 avec btn.fell() qui ne renvoie true qu’une seule fois par appui propre.
Quelle valeur de résistance pull-up choisir ?
10 kΩ est la valeur standard de référence, idéale pour 99 % des cas. 1 kΩ pour les environnements très bruyants (moteurs, contacteurs) au prix d’une consommation plus forte. 47-100 kΩ pour les projets ultra-basse consommation sur batterie. Le pull-up interne d’Arduino vaut 20-50 kΩ, ce qui est parfait dans la majorité des situations.
Comment gérer 16 boutons sans utiliser 16 broches ?
Trois solutions : (1) matrice clavier 4×4 sur 8 broches avec la librairie Keypad ; (2) chaînage de PCF8574 en I2C (16 boutons sur 2 broches) ; (3) division de tension avec résistances différentes lue sur une broche analogique unique (R-2R ladder, jusqu’à 8 boutons sur 1 broche). La matrice est la plus courante pour les claviers numériques.
Le bouton tactile capacitif TTP223 vaut-il le coup ?
Oui pour les projets premium : pas de partie mécanique (donc pas d’usure ni de rebond), détection à travers un panneau acrylique ou verre jusqu’à 5 mm. Le TTP223 expose directement un signal numérique propre, aucun debounce nécessaire. Idéal pour les interfaces de produit fini (boîtier domotique, lampe tactile, console de jeu maison). Disponible chez Didactico Tunisie.
Conclusion
Lire un bouton poussoir n’est pas trivial. C’est le sujet sur lequel les programmeurs embarqués passent leurs premières heures de débogage, et ironiquement, c’est aussi celui sur lequel ils retombent encore après dix ans d’expérience, en migrant vers un STM32 ou un ESP32-S3. Maîtrisez les cinq patterns présentés dans ce guide, ajoutez Bounce2 à votre boîte à outils, comprenez les interruptions, et 95 % des projets devient une formalité.
Chez Didactico Sfax, nous tenons en stock permanent tous les composants nécessaires : boutons tactiles 6×6 mm, poussoirs 12 mm pour panneau, TTP223 capacitifs, encodeurs rotatifs KY-040, résistances 10 kΩ, breadboards 830 points et fils Dupont mâle-femelle. Pour les étudiants ENIT, INSAT, ISBS, ISET et ESPRIT, livraison 24-48h dans toute la Tunisie. Pour aller plus loin sur Arduino, lisez notre guide complet Arduino UNO R3.
Si ce guide vous a aidé, partagez-le avec un camarade de promo qui galère encore avec les rebonds. La maîtrise du bouton, c’est le passage initiatique de tout maker.
🛒 Matériel nécessaire pour ce guide
Tout le matériel de ce tutoriel est disponible chez Didactico — livraison 24-48h partout en Tunisie, paiement à la livraison.
Bouton poussoir DS-211 bleu 10 mm 2PIN1,501 TND
Bouton poussoir momentané Vert R13-507 16 mm sans verrouillage 3A 250V1,501 TND
Led Verte 5mm Haute luminosité0,130 TND
Carte Arduino UNO R3 - Meilleure carte Arduino en Tunisie31,000 TND📘 Guides liés : Potentiomètre Arduino PWM : Contrôler une LED, un Servo et un Moteur · Feu de Signalisation LED Arduino : du Tricolore au Carrefour Intelligent
