Entrée numérique
Nous allons voir ici comment lire une information sur une broche numérique configurée en entrée - c'est à dire l'équivalent du digitalRead()
de l'Arduino.
Nous allons pour cela ajouter un bouton à notre montage qui possède déjà une LED. Si on appuie sur le bouton, on allume la LED, si on rappuie une seconde fois, on éteint la LED. On va donc faire ainsi un système de bascule. Cet exemple n'est pas si trivial qu'il n'y paraît : en effet, lorsqu’on programme dans le monde des objet, on se heure parfois à la réalité du monde physique. Nous allons voir dans cet exemple que les boutons ne sont pas parfaits. Nous verrons donc comment y remédier par le logiciel.
Premier montage
Pour commencer, nous allons faire simple : un bouton et une LED. La LED s'allumera tant que le bouton sera appuyé. Pour le montage, nous utiliserons la résistance de pull-up interne de la carte, ce qui évite de l'intégrer au montage de la breadboard. Concrètement, la broche du bouton sera tirée au niveau haut (3,3 Volts) par une résistance. Lors d'un appui, le bouton connectera la broche à la masse qui passera alors au niveau bas (0 Volts). Nous aurons ainsi une logique inversée : Appui = niveau bas.
Le bouton sera connecté à la broche D7 de la carte.
Complément :
Il est possible sur la carte adafruit de définir le bouton en pull-down et de connecter le bouton au niveau haut. Cela permet d'obtenir une logique non inversée.
Méthode : Le code
Le code pour ce premier exemple est très simple, en particulier la boucle une fois qu'on a compris la logique inversée du bouton à cause du pull-up.
La partie intéressante ici réside dans la déclaration de la broche en entrée et la configuration du pull-up. Le pull-down se définit grâce à digitalio.Pull.DOWN
bien sûr.
La propriété bouton.value
revoie l'état du bouton sous forme d'un booleen.
import time
import digitalio
import board
# déclaration des variables globales
led = digitalio.DigitalInOut(board.D13)
bouton = digitalio.DigitalInOut(board.D7)
# initialisation des divers composants du programme
led.direction = digitalio.Direction.OUTPUT
bouton.direction = digitalio.Direction.INPUT
bouton.pull = digitalio.Pull.UP
while True:
led.value = not bouton.value
Remarque :
La broche D13 est reliée à la LED rouge interne de la carte. La LED ajoutée sur la breadboard fait donc double emploi et peut être supprimée.
Amélioration du code
Nous allons à présent implémenter le système de bascule : La LED changera d'état à chaque appui sur le bouton. Pour se faire, nous allons introduire une nouvelle variable bascule
qui permet de savoir si la bascule a été faîte ou non. Cela évite à la LED de changer d'état continuellement lorsque l'on maintient le bouton enfoncé !
import time
import digitalio
import board
# déclaration des variables globales
led = digitalio.DigitalInOut(board.D13)
bouton = digitalio.DigitalInOut(board.D7)
bascule = True
# initialisation des divers composants du programme
led.direction = digitalio.Direction.OUTPUT
bouton.direction = digitalio.Direction.INPUT
bouton.pull = digitalio.Pull.UP
while True:
if not bouton.value : # Le bouton est pressé
if bascule : # La LED doit changer d'état
led.value = not led.value
bascule = False # La LED ne doit plus changer d'état
else:
bascule = True # Le bouton est relâché, la LED peut rechanger d'état
Problème du rebond
En manipulant plusieurs fois le bouton, on peut constater parfois que la LED change plusieurs fois d'état lors d'un seul appui. C'est un défaut qu'ont tous les boutons du monde réel : lorsqu'ils font contact, il y a une brève période de temps durant laquelle leur état n'est pas bien défini et oscille rapidement. C'est ce qu'on appelle le rebond. La capture ci-contre montre le phénomène capturé à l'oscilloscope. Celui-ci dure 0.5 ms.
Nous allons essayer de contrer ce phénomène.
Méthode : Méthode 1 : blocage du programme
Une première technique, très simple, consiste à utiliser la méthode time.sleep()
pour bloquer l'exécution du programme le temps que l'état du bouton se stabilise (quelques millisecondes).
import time
import digitalio
import board
# déclaration des variables globales
led = digitalio.DigitalInOut(board.D13)
bouton = digitalio.DigitalInOut(board.D7)
bascule = True
# initialisation des divers composants du programme
led.direction = digitalio.Direction.OUTPUT
bouton.direction = digitalio.Direction.INPUT
bouton.pull = digitalio.Pull.UP
while True:
if not bouton.value : # Le bouton est pressé
if bascule : # La LED doit changer d'état
led.value = not led.value
bascule = False # La LED ne doit plus changer d'état
time.sleep(0.01) # attente de 10 ms que le bouton se stabilise
else:
bascule = True # Le bouton est relâché, la LED peut rechanger d'état
Remarque : à éviter...
Cette technique n'est pas très souhaitable car elle bloque l'exécution du programme. La carte n'est donc plus active pendant un petit laps de temps. Elle ne peut donc plus capter d'éventuelles informations en provenance d'un capteur par exemple. Il est en général souhaitable d'éviter de bloquer ainsi l'exécution du programme. Nous allons voir comment faire la même chose sans blocage.
Méthode : Méthode 2 : Sans blocage
L'idée ici est de réaliser la même chose sans bloquer l'exécution du programme. Nous utiliserons donc la méthode monotonic
(équivalent de la fonction millis de l'Arduino) pour n'agir qu'une fois le temps désiré est écoulé, sans pour autant bloquer l'exécution de la boucle principale. Cela complique un peu la logique mais c'est plus propre. L'idée est de s'assurer que le bouton est resté appuyé dans un état stable pendant 10ms (0.01s) avant d'agir.
import time
import digitalio
import board
# déclaration des variables globales
led = digitalio.DigitalInOut(board.D13)
bouton = digitalio.DigitalInOut(board.D7)
bascule = True
dernierAppui = 0
# initialisation des divers composants du programme
led.direction = digitalio.Direction.OUTPUT
bouton.direction = digitalio.Direction.INPUT
bouton.pull = digitalio.Pull.UP
while True:
if not bouton.value : # Le bouton est pressé
if dernierAppui == 0: # pas d'appui anterieur détecté
# On mémorise l'instant de l'appui
dernierAppui = time.monotonic()
if bascule and dernierAppui !=0 and time.monotonic()-dernierAppui > 0.01:
# le bouton est resté appuyé assez longtemps
led.value = not led.value
bascule = False # La LED ne doit plus changer d'état
else:
dernierAppui = 0 # Le bouton est relâché, on repart de 0
bascule = True # Le bouton est relâché, la LED peut rechanger d'état
Conseil :
Amusez-vous à changer la constante de temps 0.01 pour 0.5 par exemple. Vous verrez ainsi l'effet d'annulation du rebond car vous devrez maintenir le bouton appuyé une demi seconde avant que la LED ne change d'état.
Méthode : Méthode 3 : avec une librairie dédiée - Conseillé !
Le problème de rebond étant très classique, il existe une librairie dans circuitPython qui prend en charge ce problème pour nous. Observez l'exemple de code ci-dessous. Voyez comme il s'est considérablement simplifié ! Cette méthode sera la plupart du temps à privilégier dès que vous travaillerez avec des boutons.
import time
import digitalio
import board
from adafruit_debouncer import Debouncer
# déclaration des variables globales
led = digitalio.DigitalInOut(board.D13)
broche = digitalio.DigitalInOut(board.D7)
# initialisation des divers composants du programme
led.direction = digitalio.Direction.OUTPUT
broche.direction = digitalio.Direction.INPUT
broche.pull = digitalio.Pull.UP
bouton = Debouncer(broche)
while True:
bouton.update()
if bouton.fell:
led.value = not led.value
Complément : Fonctionnement de Debouncer
Importez la librairie :
from adafruit_debouncer import Debouncer
Créez votre bouton en appelant
Debouncer(broche)
Appelez la méthode
bouton.update()
en début de boucle afin que le code scrute le bouton en permanencebouton.fell
permet de savoir que le bouton vient juste d'être pressé. Il ne renvoieTrue
qu'une seule fois par appui. C'est donc le changement d'état que l'on scrute ici.bouton.rose
permet de savoir que le bouton a été relâché. Il fonctionne commebouton.fell
. Essayez de modifier le code en remplaçantfell
parrose
et observez l'effet.bouton.value
renvoie l'état actuel du bouton.