Utilisation des interruptions en MicroPython avec une RPi Pico
Qu'est-ce qu'une interruption ?
Définition
En électronique, une interruption est un signal envoyé à un processeur qui lui indique qu’une tâche importante doit être exécutée immédiatement, interrompant ainsi le programme en cours.
Les interruptions peuvent être déclenchées de manières diverses, par exemple par un événement matériel externe, un timer
interne, etc... Elles permettent de réaliser des tâches de manière asynchrone, prioritairement au programme principal.
Les interruptions en MicroPython
Définition
En pratique, les interruptions sont généralement utilisées pour :
- Exécuter des portions de code critique lorsqu’un évènement extérieur se produit (par exemple lorsque le signal issu d'un capteur change et que cela déclenche automatiquement une fonction Python).
- Exécuter périodiquement des fonctions (par exemple pour faire clignoter une LED toutes les 5 secondes).
Sans utiliser les interruptions, il est possible de créer un script qui allume une LED quand on appuie sur un bouton. Cependant, cette méthode a deux défauts majeurs.
1 2 3 4 5 6 7 8 9 10 |
|
L'inconvénient est que le script passe son temps à surveiller la valeur de la broche pin_button
pour savoir si le bouton a été pressé.
Le script ne peut pas faire grand-chose en plus.
Si le script effectue d’autres tâches dans la boucle, il risque de manquer la pression ponctuelle du bouton.
Intêret des interruptions
L’avantage d’utiliser une interruption matérielle est qu'il n’est plus nécessaire de surveiller constamment la valeur d’un pin.
Une fonction est automatiquement exécutée lorsqu’un changement est détecté.
Avec une interruption, la boucle while
du script peut être vide.
Que ce soit avec un événement externe ou un timer
, l’interruption est déclenchée lorsqu’il y a un changement de signal.
Déclencher une interruption matérielle : les modes de détection
Evénement déclenchant une interruption
La détection d’un événement est basée sur l’allure du signal qui arrive à la broche.
Voici les différents types de détection d’interruption possibles :
Pin.IRQ_LOW_LEVEL
: Déclenche l’interruption lorsque le signal est à 0VPin.IRQ_HIGH_LEVEL
: Déclenche l’interruption lorsque le signal est à 3.3VPin.IRQ_RISING
: Déclenche l’interruption lorsque le signal passe deLOW
àHIGH
(de 0V à 3.3V)Pin.IRQ_FALLING
: Déclenche l’interruption lorsque le signal passe deHIGH
àLOW
(de 3.3V à 0V)
Note
Les modes RISING
(front montant) et FALLING
(front descendant) sont les plus couramment utilisés.
Notez que si vous utilisez les modes LOW
(état bas) et HIGH
(état haut), l’interruption se déclenchera en boucle tant que le signal ne change pas d’état.
Configuration et utilisation des interruptions en MicroPython sur la Pico
Squelette de script
Voici un squelette de script en MicroPython qui permet de déclencher une interruption externe via un signal reçu par la Pi Pico :
1 2 3 4 5 6 7 8 9 10 11 |
|
Le code utilise la fonction Pin.irq()
pour créer une demande d’interruption à partir d’un signal descendant appliqué sur la broche pin_button
.
Note
irq
signifie Interrupt Request, ou en français, demander une requête d’interruption.
On emploie également le mot isr
pour désigner la routine d’interruption, c’est-à-dire la fonction qui va être exécutée suite à l’interruption (ici elle s’appelle interruption_handler()
)
Quand une interruption se déclenche, la fonction interruption_handler()
s’exécutera automatiquement avec en argument d’entrée, le pin sur lequel l’événement a été détecté.
Il est préconisé de rédiger une fonction d’interruption (isr
) la plus rapide possible afin d’éviter de perturber le programme principal.
Par exemple, il est déconseillé d’envoyer des données via I2C, SPI directement depuis une interruption. On peut plutôt utiliser des flags, sous la forme de booléen pour stocker la détection d’un événement et le traiter ensuite dans la boucle principale.
Application : Allumer une LED quand un bouton-poussoir est pressé
Objectif
Soit le schéma de câblage suivant :
Voici le script complet qui permet de détecter lorsque l’on appuie sur un bouton avec une interruption et qui allume la LED en conséquence :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Exercice 8.1
Exécuter le programme précédent.
Note
Dans cet exemple, l’interruption se déclenche sur un front descendant.
Il est possible d’utiliser l’opérateur OU |
pour combiner les modes et que l’interruption se déclenche à la fois sur un front montant et descendant :
pin_button.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING,handler=button_isr)
Application : Utiliser des variables pour gérer les événements dans le programme principal
Objectif
On essaye de limiter le nombre d’actions effectuées au sein d’une interruption.
Il est courant d’incrémenter une variable à l’intérieur de l’ISR et d’effectuer les tâches longues dans le code principal en fonction de la valeur de cette variable.
Voici un exemple qui compte le nombre de fois que vous appuyez sur un bouton-poussoir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
On utilise une variable globale pour pouvoir écrire dans celle-ci à l’intérieur de la routine d’interruption.
Avertissement
Même si la variable est définie tout en haut du script Python, vous devez ajouter le mot-clé global
lorsque la variable est utilisée dans une fonction. Cela permet d’indiquer à l’interpréteur Python d’utiliser la variable globale plutôt que de créer localement une variable (avec le même nom) qui serait utilisée uniquement dans le contexte d’exécution de la fonction.
Exercice 8.2
Exécuter le programme précédent.