Modifications

Sauter à la navigation Sauter à la recherche
7 968 octets ajoutés ,  13 juin 2016 à 18:13
Ligne 138 : Ligne 138 :  
del( led )
 
del( led )
 
wipy.heartbeat( True )
 
wipy.heartbeat( True )
 +
</syntaxhighlight>
 +
 +
== 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 [http://arduino103.blogspot.be/2012/02/les-interruptions-sur-arduino.html 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.
 +
 +
[[Fichier:Hack-wipy-button-irq-rising.jpg|480px]]
 +
 +
==== 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.
 +
 +
[[Fichier:Hack-wipy-button-irq-falling.jpg|480px]]
 +
 +
=== Limitation des interruptions ===
 +
{{ambox-stop|text=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 {{fname|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).<br />Toutes les variables et objets doivent exister {{underline|avant}} le premier appel de la fonction callback.
 +
# ... <small>d'autres contraintes peuvent exister, référez vous à la [https://micropython.org/resources/docs/en/latest/wipy/library/machine.Pin.html documentation de MicroPython]</small> 
 +
 +
=== 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.
 +
 +
<syntaxhighlight lang="python">
 +
# 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 )
 +
</syntaxhighlight>
 +
 +
Voila, vous pouvez maintenant presser le bouton et voir la LED HeartBeat changer d'état à chaque pression.
 +
 +
Nous avons utilisé l'option {{fname|1=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
 +
<syntaxhighlight lang="python">
 +
# Appel direct de la fonction callback
 +
i()
 +
</syntaxhighlight>
 +
 +
Une interruption peut également être désactivée avec {{i.disable()}} et réactivée avec {{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.
 +
 +
[[Fichier:Switchbounce.jpg|480px]]<small><br />Exemple de contact parasite lors du relâchement d'un bouton.<br />Le même phénomène se produit lorsque le bouton est pressé.</small>
 +
 +
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.
 +
* [http://wiki.mchobby.be/index.php?title=Entr%C3%A9e_Bouton#D.C3.A9parasitage_des_boutons Déparasitage des boutons pour Arduino] (information utile en tous les cas)
 +
* [http://www.eng.utah.edu/~cs5780/debouncing.pdf 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.
 +
 +
<font color="red">Nous avons créé une classe {{fname|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'''</font>
 +
 +
Vous pouvez télécharger le fichier '''debounce.py''' et le placer directement dans le répertoire {{fname|/flash/lib/}} de votre WiPy.
 +
 +
{{download-box|Téléchargez debounce.py|http://df.mchobby.be/wipy/debounce.py}}
 +
 +
[[Fichier:Hack-wipy-button-debounce.jpg|800px]]
 +
 +
Voici comment exploiter la classe {{fname|PullUpButton}}, cet exemple attends que le bouton soit presser 5x pour sortir de la boucle de comptage.
 +
 +
<syntaxhighlight lang="python">
 +
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 )
 +
</syntaxhighlight>
 +
 +
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.
 +
 +
<nowiki>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</nowiki>
 +
 +
==== Classe PullUpButton ====
 +
Pour les plus curieux, voici l'implémentation de la classe {{fname|PullUpButton}} que vous trouverez dans le fichier {{fname|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.
 +
 +
<syntaxhighlight lang="python">
 +
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
 
</syntaxhighlight>
 
</syntaxhighlight>
    
{{HACK-WIPY-TRAILER}}
 
{{HACK-WIPY-TRAILER}}
29 917

modifications

Menu de navigation