Hack-wipy-button
Ce que nous faisons
Nous allons apprendre à lire l'état d'une entrée sur le WiPy. Pour cela, nous allons configurer une broche comme entrée (et activer la résistance pull-up). Lorsque l'utilisateur pressera la bouton, nous allumerons la LED HeartBeat de la carte pendant 3 secondes.
Pour commencer, attrapez les éléments listés ci-dessous et raccordez le tout comme indiqué. Une fois le circuit monté, vous devez charger le programme sur la carte WiPy.
Pour cet exemple, vous aurez besoin d'un WiPy, un Breadboard, un bouton poussoir et une résistance et un câble micoUSB.
Résistance Pull-up
Le but d'une résistance pull-up est de maintenir le niveau de la broche d'entrée au niveau haut (3.3v) par défaut. Cela signifie que si le montage n'impose pas une tension sur la broche, celle-ci reste au niveau haut.
Avec certains microcontrôleurs, cette résistance doit être montée par vos soins, avec d'autres (comme le WiPy) cette résistance existe dans le microcontrôleur et il suffit alors de l'activer.
Voici un petit montage (provenant d'Arduino) qui explique le fonctionnement d'une résistance pull-up de 10 KOhms.
Source: AdaFruit
Si le bouton n'est pas presser les deux résistances placent le potentiel de la broche sur 3.3v (comme il n'y a pas de courant... il n'y a pas vraiment de chute de tension dans les résistances). GP8 est donc à +3.3v.
Si le bouton est pressé, la broches GP8 est ramenée à la masse (0V) par l'intermédiaire de la résistance de 100 Ohms. La résistance de 10KOhms est alors également branchée à la masse, ce qui fait qu'un courant de 3.3 / 10000 = 0.33mA y passe (négligeable).
La résistance de 100 Ohms est une résistance de protection et n'est pas obligatoire. Elle est par ailleurs rarement utilisée par les habitués. Prenez la cas ou vous avez configuré la broche en sortie, placée au niveau haut (3.3v) par votre programme. Si vous pressez le bouton sans résistance de sortie et que vous pressiez le bouton? Et bien, s'il n'y avait pas la résistance de 100 Ohms, vous auriez un court-circuit franc, ce qui endommagerait votre WiPy. S'il y a une résistance de 100 Ohms, vous n'avez plus de court-circuit mais un courant de 3.3V / 100 = 33 mA (beaucoup de trop pour une sortie WiPy mais il s'es sortira peut être si vous n'insistez pas).
Le bouton tactile
Dans les montages présentés ci-dessous, le bouton tactile proposé par MC Hobby peut se monter très facilement.
Sa forme carrée peut laisser penser qu'il est facile de monter le bouton "de travers" puisqu'il est facile de le tourner d'un quart de tour, un demi tour.
Il n'est pourtant pas nécessaire d'avoir recourt à un multimètre pour être certain du montage, tout soucis de mauvais raccordement peut facilement être écarté en utilisant le principe suivant:
"Toujours utiliser les bornes de deux coins totalement opposés pour effectuer le raccordement" (simple et efficace)
Vous constaterez dans l'exemple ci-dessus que même si le bouton est tourné d'un quart de tour (à droite de l'image), la position des points de raccordements (en bleu) font que ce dernier opère toujours correctement. Il n'y a ni court-circuit, ni dysfonctionnement :-) .
Matériel nécessaire
Bouton poussoir
x1
Schéma
Voici le schéma correspondant à nos raccordement.
Brancher
Connectez tous les éléments ensembles comme présenté sur l'image.
Made with - réalisé avec - Fritzing fritzing.org
Programme simple
Lire l'état du bouton
Pour lire l'état du bouton, vous devez déclarer la broche en entrée et activer la résistance pull-up (voyez l'explication en début d'article)
from machine import Pin
gp8 = Pin( 'GP8', mode=Pin.IN, pull=Pin.PULL_UP )
Pour lire la valeur de la broche, vous pouvez utiliser les deux possibilités suivantes:
gp8()
gp8.value()
Dans les deux cas, la fonction retourne:
- 0 si la broche est au niveau bas
- 1 si la broche est au niveau haut
Attention: logique inversée
Etant donné que le bouton utilise le montage pull-up (voyez en début de tutoriel) gp8.value() retourne une valeur en logique inversée. |
La broche GP8 sera:
- au niveau haut (3.3v) lorsque personne ne presse sur le bouton
- au niveau bas (0v) lorsque quelqu'un presse le bouton
L'appel gp8.value() retourne donc un valeur en logique inversée:
- 1: signifie que le bouton N'EST PAS pressé
- 0: signifie que le bouton EST pressé
Exemple
# Cet exemple controle la LED heartbeat et la fait clignoter jusqu'à ce que l'on presse
# sur le bouton raccordé sur GP8.
# Le but est d'apprendre a utiliser une entrée du WiPy avec un bouton
#
#
# Ou acheter un WiPy et une carte d'extension
# http://shop.mchobby.be/product.php?id_product=736
# http://shop.mchobby.be/product.php?id_product=737
# http://shop.mchobby.be/category.php?id_category=68
#
# Voyez le tutoriel
# http://wiki.mchobby.be/index.php?title=Hack-wipy-button
#
# Auteur: Meurisse D. pour shop.mchoby.be
# Licence: CC-BY-SA
#
from machine import Pin
import time
import wipy
# Desactiver HeartBeat + reconfigurer
wipy.heartbeat( False )
led = Pin( 'GP25', mode=Pin.OUT )
led.value( 0 )
# Declare la broche en entrée
gp8 = Pin( 'GP8', mode=Pin.IN, pull=Pin.PULL_UP )
# tant que le bouton n'est pas pressé
while gp8.value() == 1:
led.toggle() # changer etat led
time.sleep_ms( 200 ) # attendre 0.2 sec
# Eteindre la LED
led.value( 0 )
# Réactiver heartbeat
del( led )
wipy.heartbeat( True )
Interruption et callback
Ce qui serait idéal, c'est d'appeler automatiquement une fonction lorsque le bouton est pressé. Une telle fonction est appelée fonction callback.
Nous allons utiliser le principe d'interruption qui permet d'interrompre le programme principal lorsqu'une broche change d'état.
Le processus d'interruption appel alors une fonction (dite fonction de rappel ou fonction callback) qui effectue la tâche attendue puis rend la main au système.
Mode d'interruption
il y a plusieurs modes d'interruption (comme décrits dans cet article Arduino), les plus utilisés sont:
Les flans montant (dit "rising")
L'interruption est déclenchée (voir la flèche bleue) lorsque le signal passe du niveau bas au niveau haut.
Les flans descendant (dit "falling")
L'interruption est déclenchée (voir la flèche bleue) lorsque le signal passe du niveau bas au niveau haut.
Limitation des interruptions
Une interruption et l'éxecution de la fonction callback reste un processus exceptionnel qui prend place (qui s'insère sauvagement) dans l'exécution d'un programme principal. Il y a donc des limitations et contraintes à l'utilisation d'une fonction d'interruption avec MicroPython |
- Vous ne pouvez pas utiliser la fonction print() dans la fonction de callback. Il ne se passera rien.
- Vous ne pouvez pas faire d'allocation de mémoire dans la fonction d'interruption (cela pourrait changer dans le futur).
Toutes les variables et objets doivent exister avant le premier appel de la fonction callback. - ... d'autres contraintes peuvent exister, référez vous à la documentation de MicroPython
Exemple
Dans cet exemple nous allons prendre le contrôle de la LED HeartBeat et la faire changer d'état à chaque fois que l'on presse sur le bouton raccorder sur GP8.
# Cet exemple utilise les interruption et callback pour changer l'état de
# la LED heartbeat à chaque fois que le bouton branché sur GP8 est pressé.
#
#
# Ou acheter un WiPy et une carte d'extension
# http://shop.mchobby.be/product.php?id_product=736
# http://shop.mchobby.be/product.php?id_product=737
# http://shop.mchobby.be/category.php?id_category=68
#
# Voyez le tutoriel
# http://wiki.mchobby.be/index.php?title=Hack-wipy-button
#
# Auteur: Meurisse D. pour shop.mchoby.be
# Licence: CC-BY-SA
#
from machine import Pin
import wipy
# Réutilisation de la LED heartbeat
wipy.heartbeat( False )
led = Pin( 'GP25', mode=Pin.OUT )
led.value( 0 )
# Definir la fonction callback pour
# inverser l'etat de la LED Heartbeat
#
def pincb( pin ):
led.toggle()
# Definir la broche GP8 comme entrée et activer
# la résistance pull-up
p8 = Pin( 'GP8', mode=Pin.IN, pull=Pin.PULL_UP )
# Définir l'interruption sur flanc descendant (falling) pour
# appeler la fonction callback
i = p8.irq( trigger=Pin.IRQ_FALLING, handler=pincb )
Voila, vous pouvez maintenant presser le bouton et voir la LED HeartBeat changer d'état à chaque pression.
Nous avons utilisé l'option trigger=Pin.IRQ_FALLING car l'entrée est configurée en Pull-Up. L'entrée GP8 est donc continuellement au niveau haut... et passe au niveau bas lorsque l'on presse sur le bouton poussoir. Il faut donc détecter le flanc descendant du signal.
Tel que définit ci-avant, il est possible de déclencher la fonction callback directement
# Appel direct de la fonction callback
i()
Une interruption peut également être désactivée avec Modèle:I.disable() et réactivée avec Modèle:I.enable().
Déparasitage des boutons
Vous aurez certainement remarqué que, suivant les cas, la LED heartbeat change d'état une ou plusieurs fois même si vous pressez une seule fois le bouton.
Cela arrive souvent avec les boutons mécaniques où le contact n'est pas franc mais passer pas une phase transitoire avec plusieurs rebond avant le contact définitif.
Exemple de contact parasite lors du relâchement d'un bouton.
Le même phénomène se produit lorsque le bouton est pressé.
Ce sont ces rebonds qui déclenchent plusieurs fois l'interruption.
Déparasitage des boutons
Il y a différentes techniques de déparasitages. Si vous utilisez les interruptions & callback, vous aurez besoin d'utiliser une méthode de déparasitage matérielle.
- Déparasitage des boutons pour Arduino (information utile en tous les cas)
- http://www.eng.utah.edu/~cs5780/debouncing.pdf (anglais) - document très intéressant avec explications détaillées et différentes techniques de déparasitage.
déparasitage logiciel
Si vous avez lisez l'état du bouton dans votre programme, vous pourrez utiliser une méthode de déparasitage logiciel comme celle-ci utilisé ci-dessous.
Nous avons créé une classe PullUpButton qui fait du déparasitage logiciel sur une entrée équipée d'un bouton avec résistance pull-up. Cette classe est stockée dans le fichier debounce.py
Vous pouvez télécharger le fichier debounce.py et le placer directement dans le répertoire /flash/lib/ de votre WiPy.
Voici comment exploiter la classe PullUpButton, cet exemple attends que le bouton soit presser 5x pour sortir de la boucle de comptage.
from debounce import PullUpButton
import time
btn = PullUpButton( 'GP8' )
counter=0
while counter < 5:
print( 'presser le bouton svp' )
while not btn.is_pressed():
time.sleep_ms( 100 )
counter=counter+1
print( 'counter = %i' % counter )
ce qui produit le résultat suivant après exactement 5 pressions physiques sur le bouton... les rebonds de contact ne viennent plus nous importuner.
presser le bouton svp counter = 1 presser le bouton svp counter = 2 presser le bouton svp counter = 3 presser le bouton svp counter = 4 presser le bouton svp counter = 5
Classe PullUpButton
Pour les plus curieux, voici l'implémentation de la classe PullUpButton que vous trouverez dans le fichier debounce.py.
Vous pouvez clairement y voir une seconde relecture de l'entrée après un délais de 10 millisecondes. C'est là qu'intervient le déparasitage logicielle de l'entrée.
from machine import Pin
import time
class PullUpButton:
""" Classe pour gérer un bouton pull-up sur une broche X.
Détecte lorsque la broche passe à 0 """
p = None # Pin object
state = None # Last known state
def __init__( self, button_pin ):
self.p = Pin( button_pin, Pin.IN, pull=Pin.PULL_UP )
self.state = self.p.value()
def is_pressed(self):
""" vérifie si le bouton est pressé / détecte le changement
d'état. Ne sera signalé qu'une seule fois! """
val = self.p.value()
result = False
if val != self.state:
# relecture dans 10 ms (deboucing)
time.sleep_ms( 10 )
val2 = self.p.value()
if val == val2: # valeur stable :)
self.state = val
result = (val == 0) # Is pressed
return result