Aller au contenu principal

Les entrées : boutons et capteurs

Ce que ce chapitre apporte 5 points
  • Lire l'état d'une entrée numérique, et expliquer pourquoi une entrée non reliée rend n'importe quoi.
  • Choisir entre une résistance de tirage externe et INPUT_PULLUP, et prévoir la valeur lue au repos et à l'appui.
  • Détecter un appui plutôt qu'un état, et compter les appuis sans être trompé par les rebonds.
  • Convertir une lecture analogique en tension, et une tension en lecture.
  • Ramener une lecture à une autre échelle avec map, en connaissant ses arrondis et ses limites.

Écrire sur une broche est facile : la carte impose 5 V ou 0 V, et la LED obéit. Lire est plus délicat, parce que le monde physique ne se présente pas proprement. Une entrée que rien ne relie flotte et rend n'importe quoi, un bouton qui se ferme rebondit pendant quelques millisecondes, un capteur délivre une tension continue qu'il faut ramener à un nombre. Ce chapitre traite ces trois difficultés, dans l'ordre où elles surviennent.

Une entrée numérique

digitalRead(broche) rend HIGH ou LOW selon la tension présente sur la broche. Sur l'Uno alimentée en 5 V, une tension supérieure à environ 3 V est lue HIGH, une tension inférieure à environ 1,5 V est lue LOW.

Définition

Une entrée est flottante quand rien ne la relie à une tension définie. Elle se comporte alors comme une antenne : les parasites, la proximité d'une main, le voisinage d'un fil suffisent à faire changer sa lecture.

Le montage naïf, un bouton entre la broche et le 5 V, produit exactement cette situation. Bouton enfoncé, la broche est à 5 V et lit HIGH. Bouton relâché, elle n'est plus reliée à rien, et sa lecture est indéfinie : elle peut rester haute, retomber, osciller.

La résistance de tirage

La solution consiste à relier la broche, au repos, à une tension connue, à travers une résistance assez forte pour que le bouton l'emporte quand il est enfoncé.

MontageAu reposBouton enfoncéConfiguration
Résistance de 10 kΩ vers GND, bouton vers 5VLOWHIGHpinMode(2, INPUT)
Résistance interne vers 5 V, bouton vers GNDHIGHLOWpinMode(2, INPUT_PULLUP)

Le second montage est le plus employé : il n'ajoute aucun composant, la résistance étant intégrée au microcontrôleur. Il a une contrepartie, qui trompe systématiquement la première fois : la logique est inversée. Un bouton enfoncé se lit LOW.

Le bouton-poussoir le plus courant a quatre pattes, et non deux. Elles vont par paires reliées en interne : les deux pattes d'une même paire sont toujours au même potentiel, et l'appui relie une paire à l'autre. Il se pose à cheval sur la tranchée centrale de la plaque d'essai, une paire de chaque côté. Posé tourné d'un quart de tour, il relie par sa paire interne les deux points que l'appui devait réunir : c'est un court-circuit permanent, et le bouton ne sert plus à rien. Le montage de départ « Le bouton-poussoir tourné » de la plaque d'essai montre cette erreur.

Les deux montages s'essaient sur la plaque d'essai de la salle machine : ses montages de départ « Un bouton qui flotte » et « Un tirage vers la masse, posé à la main » montrent la broche indéfinie, puis la même broche rendue fiable par la résistance, et la lecture change au clic sur le bouton.

Pourquoi une résistance suffit

La résistance de tirage et le bouton forment ensemble un pont diviseur de tension, celui du parcours d'électricité, avec la broche au point milieu. Un bouton se modélise honnêtement comme une résistance : presque nulle quand ses lames se touchent, énorme quand un espace d'air les sépare. La tension de la broche se partage alors entre les deux, dans le rapport de leurs valeurs.

La résistance interne de l'Uno vaut entre 20 et 50 kΩ selon la fiche du microcontrôleur ; la figure en prend 30.

E5 ViEuEMRtirage30 kΩiRtirageuRtirageRbouton1 MΩiRboutonuRboutonAB
1 MΩ
Valeurs déclarées et grandeurs calculées, composant par composant
ComposantValeurTensionCourantPuissance
EM → A5 V5 V4,85 µA24,3 µW
RtirageA → B30 kΩ146 mV4,85 µA707 nW
RboutonB → M1 MΩ4,85 V4,85 µA23,6 µW

Potentiels : A = 5 V, B = 4,85 V, M = 0 V. Les grandeurs en gras sont calculées, dans l'orientation portée par les flèches ; une valeur négative signale un sens inverse de celui de la flèche.

INPUT_PULLUP vu comme un pont diviseur. La broche est le nœud B. Faire varier la résistance du bouton, d'un contact franc à un espace d'air, et lire la tension de la broche.
À manipuler
Placer le curseur tout en haut, bouton ouvert : la tension de la broche approche 5 V, bien au-dessus du seuil de 3 V, et se lit HIGH. Le descendre tout en bas, contact franc : elle tombe à presque rien, sous le seuil de 1,5 V, et se lit LOW. Chercher ensuite la valeur du bouton qui place la broche entre 1,5 et 3 V : c'est la zone où digitalRead ne garantit plus rien. Elle correspond à un contact dont la résistance est du même ordre que celle de tirage, ce qui est exactement l'état d'un bouton qui rebondit, ou d'un doigt posé sur la broche.

La leçon tient au rapport des deux résistances, pas à leur valeur exacte. Tant que le bouton fermé vaut bien moins que la résistance de tirage, et le bouton ouvert bien plus, la broche est franchement haute ou franchement basse. C'est aussi pour cela que la résistance de tirage se choisit forte : bouton fermé, elle est parcourue par un courant de 5/30 0005 / 30\,000 A, soit environ 170 µA par la loi d'Ohm. Une résistance cent fois plus faible gaspillerait cent fois plus de courant pour le même résultat logique.

Arduino
const int BOUTON = 2;
const int LED = 13;
void setup() {
pinMode(BOUTON, INPUT_PULLUP); // bouton entre la broche 2 et GND
pinMode(LED, OUTPUT);
}
void loop() {
if (digitalRead(BOUTON) == LOW) { // LOW signifie enfoncé
digitalWrite(LED, HIGH);
} else {
digitalWrite(LED, LOW);
}
}
Vérification rapideon peut se reprendre

1.Une broche configurée en INPUT n'est reliée à rien. Que rend digitalRead ?

2.Avec INPUT_PULLUP et un bouton relié à la masse, que lit-on bouton enfoncé ?

Un état n'est pas un appui

Compter les appuis semble simple : incrémenter un compteur quand le bouton est enfoncé. Mais loop() s'exécute des dizaines de milliers de fois par seconde, et un appui humain dure un dixième de seconde. Tester l'état fait donc compter des milliers d'appuis pour une seule pression.

Ce qu'il faut détecter, c'est le changement d'état : le moment où la lecture passe de relâché à enfoncé. On garde pour cela la lecture précédente, et l'on compare.

Arduino
const int BOUTON = 2;
int precedent = HIGH; // INPUT_PULLUP : relâché se lit HIGH
int appuis = 0;
void setup() {
Serial.begin(9600);
pinMode(BOUTON, INPUT_PULLUP);
}
void loop() {
int etat = digitalRead(BOUTON);
if (etat == LOW && precedent == HIGH) { // on vient d'enfoncer le bouton
appuis++;
Serial.println(appuis);
}
precedent = etat;
}

Les rebonds

Ce programme compte encore trop, et la raison est mécanique. Quand deux lames métalliques se touchent, elles rebondissent pendant quelques millisecondes : le contact s'établit, se rompt, s'établit de nouveau. Chaque rebond est un vrai changement d'état, que le programme compte comme un appui.

2 ms par bit500 bauds32 bits, 64 ms en tout
lecture brute00101011111111111111111111111111état retenu00000000000000000000011111111111dernier rebondstable depuis 30 ms016 ms32 ms48 ms64 ms
Un appui vu par la broche, sur 64 ms (ici avec un montage où l'appui se lit HIGH). La lecture brute change cinq fois en douze millisecondes. L'état retenu ne change qu'une fois, lorsque la lecture n'a plus bougé pendant 30 ms.
L'anti-rebond qui oublie le relâchement
Ajouter un delay(50) juste après avoir compté un appui paraît régler le problème : les rebonds de l'appui tombent pendant la pause. Mais le bouton rebondit aussi quand on le relâche, et ces rebonds-là produisent un nouveau front, compté comme un second appui. Une simulation d'un seul appui avec rebonds donne ainsi 2 au lieu de 1.

La méthode fiable ne se fie pas au premier changement : elle n'accepte un nouvel état que s'il est resté stable pendant un délai fixé, à l'appui comme au relâchement.

Mesurer cette stabilité demande une horloge. millis() rend le nombre de millisecondes écoulées depuis le démarrage de la carte, comme une heure qui ne fait qu'avancer. Le programme mémorise l'instant du dernier changement de lecture, et la différence millis() - dernierChangement donne le temps écoulé depuis : dès qu'elle atteint 30 ms, la lecture est jugée stable. Cet instant se range dans un unsigned long, parce qu'un int de 16 bits déborderait au bout de 32 secondes ; le chapitre millis() et machines à états explique pourquoi cette forme soustractive reste juste quand millis() revient à zéro.

Arduino
const int BOUTON = 2;
const unsigned long STABLE_MS = 30; // durée de stabilité exigée
int lectureBrute = HIGH; // dernière lecture, même instable
int etatStable = HIGH; // état accepté après stabilité
unsigned long dernierChangement = 0;
int appuis = 0;
void setup() {
Serial.begin(9600);
pinMode(BOUTON, INPUT_PULLUP);
}
void loop() {
int lecture = digitalRead(BOUTON);
if (lecture != lectureBrute) { // la lecture bouge : on relance le chronomètre
lectureBrute = lecture;
dernierChangement = millis();
}
if (millis() - dernierChangement >= STABLE_MS && lectureBrute != etatStable) {
etatStable = lectureBrute; // stable depuis 30 ms : on l'accepte
if (etatStable == LOW) { // et c'est un appui
appuis++;
Serial.println(appuis);
}
}
}

Ce programme compte un appui par pression, quels que soient les rebonds, et ignore une impulsion parasite plus courte que 30 ms. Il n'emploie aucun delay : il ne bloque jamais le reste du programme, ce que le chapitre 7 généralise.

Vérification rapideon peut se reprendre

Pourquoi un bouton mécanique produit-il plusieurs changements d'état pour un seul appui ?

Une entrée analogique

Un capteur de température, de lumière, un potentiomètre ne délivrent pas deux états mais une tension continue. Les broches A0 à A5 la mesurent.

Définition

analogRead(broche) convertit la tension présente, entre 0 et 5 V, en un entier de 0 à 1023. Le convertisseur travaille sur 10 bits, soit 1024 valeurs possibles.

La convention employée dans ce parcours fait correspondre 5 V à la valeur maximale :

lecture=tension×10235tension=lecture×51023\text{lecture} = \text{tension} \times \frac{1023}{5} \qquad \text{tension} = \text{lecture} \times \frac{5}{1023}

Un palier représente donc environ 4,9 mV : c'est la plus petite variation de tension que la carte puisse distinguer. Une lecture de 512 correspond à 2,50 V, une lecture de 768 à 3,75 V.

Le potentiomètre est le capteur le plus simple : ses deux extrémités vont au 5 V et à la masse, son curseur à A0, et tourner le bouton fait varier la tension du curseur de 0 à 5 V. C'est encore un pont diviseur : la piste résistive est coupée en deux par le curseur, et tourner le bouton déplace le point de coupure. La somme des deux moitiés ne change pas, seul leur rapport change, et c'est lui qui fixe la tension lue.

Un capteur résistif, photorésistance ou thermistance, ne fournit pas de tension : il change seulement de résistance. Branché seul sur A0, il ne donne rien d'utilisable. Il lui faut une résistance fixe pour former le pont diviseur : la photorésistance va du 5 V à A0, une résistance de 10 kΩ va de A0 à la masse, et A0 lit le point milieu. Une photorésistance vaut environ 1 kΩ en plein jour : la tension lue est alors 5×10/(10+1)≈4,555 \times 10 / (10 + 1) \approx 4{,}55 V, soit une lecture d'environ 930. Dans l'ombre, elle monte vers 50 kΩ : la tension tombe à 5×10/(10+50)≈0,835 \times 10 / (10 + 50) \approx 0{,}83 V, soit une lecture d'environ 170. Plus il y a de lumière, plus la lecture est grande.

E5 ViEuEMRlumiere10 kΩiRlumiereuRlumiereRfixe10 kΩiRfixeuRfixeAB
10 kΩ
Valeurs déclarées et grandeurs calculées, composant par composant
ComposantValeurTensionCourantPuissance
EM → A5 V5 V250 µA1,25 mW
RlumiereA → B10 kΩ2,5 V250 µA625 µW
RfixeB → M10 kΩ2,5 V250 µA625 µW

Potentiels : A = 5 V, B = 2,5 V, M = 0 V. Les grandeurs en gras sont calculées, dans l'orientation portée par les flèches ; une valeur négative signale un sens inverse de celui de la flèche.

Une photorésistance en pont diviseur. Rlumiere est la photorésistance, Rfixe la résistance de 10 kΩ, et A0 lit le nœud B. Faire varier la photorésistance du plein jour, 1 kΩ, à l'ombre, 50 kΩ.

Changer d'échelle avec map

Il faut souvent ramener une lecture à une autre échelle : de 0 à 1023 vers 0 à 255 pour piloter une LED, ou vers un pourcentage. map fait cette règle de trois.

Arduino
void setup() {
Serial.begin(9600);
}
void loop() {
int lecture = analogRead(A0); // de 0 à 1023
int pourcent = map(lecture, 0, 1023, 0, 100); // de 0 à 100
Serial.println(pourcent);
delay(200);
}
Deux propriétés de map à connaître
map calcule en entiers et tronque : map(768, 0, 1023, 0, 255) rend 191, alors que le calcul exact donne 191,4. Elle ne borne pas non plus son résultat : une valeur hors de l'échelle de départ donne une valeur hors de l'échelle d'arrivée, map(1100, 0, 1023, 0, 255) rendant 274. Quand l'entrée peut sortir de sa plage, constrain ramène le résultat dans les bornes.
Vérification rapideon peut se reprendre

1.Quelle tension correspond à une lecture de 512 ?

2.Combien de valeurs différentes analogRead peut-elle rendre ?

3.Que rend map(1100, 0, 1023, 0, 255) ?

Mettre en pratique

Un bouton relie la broche 2 à la masse, configurée en INPUT_PULLUP. Que lit digitalRead au repos, bouton enfoncé, et que lirait-elle en INPUT simple ?

Au repos, la résistance interne tire la broche vers le 5 V : HIGH. Bouton enfoncé, la broche est reliée à la masse : LOW. La logique est inversée par rapport à l'intuition.

En INPUT simple, aucune résistance ne tire la broche au repos : elle flotte, et sa lecture est indéfinie. Le programme peut sembler fonctionner un moment, puis réagir à un appui fantôme quand on approche la main.

Un programme incrémente un compteur dès que digitalRead(2) == LOW. Un appui d'un dixième de seconde fait monter le compteur de plusieurs milliers. Pourquoi, et quelle est la correction ?

Le programme compte un état, pas un appui. loop() tourne des milliers de fois pendant que le bouton est enfoncé, et chaque tour ajoute 1.

La correction compare la lecture courante à la précédente, et ne compte que le passage de HIGH à LOW. Pour ne pas être trompé par les rebonds, ce changement n'est accepté que si la lecture est restée stable une trentaine de millisecondes, à l'appui comme au relâchement.

Un potentiomètre donne une lecture de 768. Quelle tension cela représente-t-il, et que rend map(768, 0, 1023, 0, 255) ?

La tension vaut 768×5/1023≈3,75768 \times 5 / 1023 \approx 3{,}75 V.

map calcule 768×255/1023=191,4768 \times 255 / 1023 = 191{,}4 et tronque : elle rend 191. Diviser la lecture par 4, un raccourci fréquent, rendrait 192 : les deux méthodes diffèrent d'une unité, ce qui est sans conséquence pour une luminosité, mais pas pour une comparaison à un seuil exact.

Pourquoi un delay(50) placé juste après le comptage d'un appui ne suffit-il pas à supprimer les rebonds ?

La pause absorbe les rebonds qui suivent l'appui. Mais le contact rebondit aussi au relâchement : la lecture repasse brièvement à l'état enfoncé, ce qui fait un nouveau front, compté comme un nouvel appui.

Une seule pression est alors comptée deux fois. La méthode par état stable règle les deux cas à la fois, puisqu'elle attend que la lecture ait cessé de bouger avant d'accepter un changement, dans un sens comme dans l'autre.

Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?

Dans la bibliothèque d'exercices