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éthodeLe 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.

1
import time
2
import digitalio
3
import board
4
5
# déclaration des variables globales
6
led = digitalio.DigitalInOut(board.D13)
7
bouton = digitalio.DigitalInOut(board.D7)
8
9
# initialisation des divers composants du programme
10
led.direction = digitalio.Direction.OUTPUT
11
bouton.direction = digitalio.Direction.INPUT
12
bouton.pull = digitalio.Pull.UP 
13
14
while True:
15
    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é !

1
import time
2
import digitalio
3
import board
4
5
# déclaration des variables globales
6
led = digitalio.DigitalInOut(board.D13)
7
bouton = digitalio.DigitalInOut(board.D7)
8
bascule = True
9
10
# initialisation des divers composants du programme
11
led.direction = digitalio.Direction.OUTPUT
12
bouton.direction = digitalio.Direction.INPUT
13
bouton.pull = digitalio.Pull.UP 
14
15
while True:
16
    if not bouton.value :   # Le bouton est pressé
17
        if bascule :        # La LED doit changer d'état
18
            led.value = not led.value
19
            bascule = False # La LED ne doit plus changer d'état
20
    else:
21
        bascule = True      # Le bouton est relâché, la LED peut rechanger d'état
22

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éthodeMé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).

1
import time
2
import digitalio
3
import board
4
5
# déclaration des variables globales
6
led = digitalio.DigitalInOut(board.D13)
7
bouton = digitalio.DigitalInOut(board.D7)
8
bascule = True
9
10
# initialisation des divers composants du programme
11
led.direction = digitalio.Direction.OUTPUT
12
bouton.direction = digitalio.Direction.INPUT
13
bouton.pull = digitalio.Pull.UP 
14
15
while True:
16
    if not bouton.value :    # Le bouton est pressé
17
        if bascule :         # La LED doit changer d'état
18
            led.value = not led.value
19
            bascule = False  # La LED ne doit plus changer d'état
20
            time.sleep(0.01) # attente de 10 ms que le bouton se stabilise
21
    else:
22
        bascule = True       # Le bouton est relâché, la LED peut rechanger d'état
23

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éthodeMé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.

1
import time
2
import digitalio
3
import board
4
5
# déclaration des variables globales
6
led = digitalio.DigitalInOut(board.D13)
7
bouton = digitalio.DigitalInOut(board.D7)
8
bascule = True
9
dernierAppui = 0
10
11
# initialisation des divers composants du programme
12
led.direction = digitalio.Direction.OUTPUT
13
bouton.direction = digitalio.Direction.INPUT
14
bouton.pull = digitalio.Pull.UP 
15
16
while True:
17
    if not bouton.value :    # Le bouton est pressé
18
        if dernierAppui == 0:   # pas d'appui anterieur détecté
19
            # On mémorise l'instant de l'appui
20
            dernierAppui = time.monotonic() 
21
            
22
        if bascule and dernierAppui !=0 and time.monotonic()-dernierAppui > 0.01:
23
            # le bouton est resté appuyé assez longtemps
24
            led.value = not led.value
25
            bascule = False  # La LED ne doit plus changer d'état
26
    else:
27
        dernierAppui = 0        # Le bouton est relâché, on repart de 0
28
        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éthodeMé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.

1
import time
2
import digitalio
3
import board
4
from adafruit_debouncer import Debouncer
5
6
# déclaration des variables globales
7
led = digitalio.DigitalInOut(board.D13)
8
broche = digitalio.DigitalInOut(board.D7)
9
10
# initialisation des divers composants du programme
11
led.direction = digitalio.Direction.OUTPUT
12
broche.direction = digitalio.Direction.INPUT
13
broche.pull = digitalio.Pull.UP
14
bouton = Debouncer(broche)
15
16
while True:
17
    bouton.update()
18
    if bouton.fell:
19
        led.value = not led.value

ComplémentFonctionnement 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 permanence

  • bouton.fell permet de savoir que le bouton vient juste d'être pressé. Il ne renvoie True 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 comme bouton.fell. Essayez de modifier le code en remplaçant fell par rose et observez l'effet.

  • bouton.value renvoie l'état actuel du bouton.