Les broches d'interruption
Sommaire du chapitre
- Les broches d'interruption
- Présentation
- Évènements d'interruption
- Chronogrammes d'interruption
- Les broches disponibles
- Exemple avec les capteur PIR
- Utilisation
- Code PIR sans interruption
- Code PIR avec interruption
- Mise en pratique avec la carte CREPP.io
- Branchements
- Les variables volatiles
- Mise en pratique avec une carte ESP12 hors CREPP.io
- Schéma de l'exemple
- Code C++ basique
- Code C++ avancé
Les broches d'interruption
Présentation
Dans certains cas, il est souhaitable de récupérer la valeur d'une broche à tout moment du programme, même quand celui ci est occupé dans une tâche et même dans une fonction de temporisation [1].
Pour remédier à ce problème, on peut utiliser les broches d'interruption qui permettent de récupérer la main sur l'ensemble du programme lorsque'un évènement survient sur une broche.
Concrètement, lorsque un évènement e survient sur la broche b, la fonction f est appelée, quelque soit l'état du programme principal.
Un évènement est une modification de l'état de la broche.
Évènements d'interruption
Il existe différents états pour les broches :RISING: front montant
FALLING: Front descendant
CHANGE: Front montant puis descendant ou descendant puis montant
Chronogrammes d'interruption
Lorsqu'un évènement déterminé survient sur une broche, le code principal va se mettre en pause et la fonction spéciale sera appelée. Une fois cette fonction terminée, le code principale reprend son traitement là où il s'est arrêté.Les broches disponibles
Pour les cartes Arduino Uno, il est possible d'utiliser les broches D2 et D3 en tant que broche d'interruption.
Pour les cartes Arduino Mega, il y a plus de broches, pour plus d'informations, se reporter au lien suivant : excepté la broche GPIO 16.
Notes
Voir delay(), delayMicroseconds()
↑
Exemple avec les capteur PIR
Cette exemple est valable avec une carte Arduino.
Par exemple, on souhaite réagir prioritairement à un capteur PIR quel que soit l'état du programme.
Les capteurs PIR détectent les rayonnements infrarouges émis par un objet.
Puisque tout objet émet un rayonnement infrarouge, le capteur PIR est muni de deux cellules sensibles aux infrarouges qui vont détecter ces rayons infrarouges réfléchit ou émit par l'objet.

Le cache blanc, qui couvre et protège généralement le capteur, est une lentille de Fresnel avec plusieurs facettes qui permet de concentrer le rayonnement infrarouge sur les cellules.
Utilisation
Ces capteurs possèdent une broche de sortie qui est mise à l'état HAUT pendent une certaine durée [1] lorsqu'il y a détection d'un mouvement.Nous allons présenter un code réalisé sans interruption et un autre qui utilise les interruptions.
Code PIR sans interruption
Voici un code d'exemple pour réagir dès qu'une présence est détectée.
#define LED 13 //Broche de la LED
#define OUT 2 //Broche du capteur PIR
void setup()
pinMode(LED, OUTPUT); //LED en sortie
pinMode(OUT, INPUT); //Broche du capteur en entrée
Serial.begin(9600); //Vitesse de communication à 9600 bauds
//End setup
void loop(){
outValue = digitalRead(OUT); //Lire létat du capteur
if (outValue == HIGH) //Détection d'un mouvement
Serial.println("Detection");
//End else
}//End loop
Maintenant, supposons que la carte exécute un programme qui prend plusieurs secondes. Comment faire ?
On peut utiliser une interruption externe.
Code PIR avec interruption
#define LED 13 //Broche de la LED
#define OUT 2 //Broche du capteur PIR
void setup()
Serial.begin(9600);//Vitesse de communication à 9600 bit/s
pinMode(LED, OUTPUT); //LED en sortie
pinMode(OUT, INPUT); //Broche du capteur en entrée
attachInterrupt(digitalPinToInterrupt(OUT), presence, RISING); //Appel de la fonction presence à chaque changement de front du bouton
Serial.println("Init");
void loop()
delay(5000); //Pause du programme principal
void presence()
Serial.println("Presence !");
Notes
Cette durée est réglable avec le potentiomètre sur le capteur
↑
Mise en pratique avec la carte CREPP.io
En dernier exemple, prenons le cas d'un bouton qui doit changer l'état d'une LED à n'importe quel moment du programme :

Branchements

Il ne faut pas oublier de mettre les jumpers sur la carte (D5, D6 et D7)
Les variables volatiles
Avant d'examiner le code, il est essentiel de comprendre l'utilité du mot-clé volatile. Dans notre exemple de contrôle d'une LED, une variable partagée sera modifiée à la fois par le programme principal et par une interruption (ISR).
Sans indication explicite, le compilateur pourrait optimiser l'accès à cette variable en la mettant en cache dans un registre, supposant que sa valeur ne change qu'au sein du flux d'exécution actuel. Or, une ISR peut modifier cette variable de manière imprévisible pour le programme principal. Pour empêcher cette optimisation et garantir que chaque accès lit toujours la valeur actuelle en mémoire, nous utilisons le mot-clé volatile.
Ainsi, le compilateur sera contraint de lire systématiquement la valeur en mémoire à chaque utilisation, assurant la cohérence des données entre le programme principal et l'interruption.
volatile int state = LOW;
Code pour les interruptions
Mise en pratique avec une carte ESP12 hors CREPP.io
Nous souhaitons réagir de manière prioritaire à l'appui d'un bouton poussoir. Cet appui inversera l'état actuel de la LED interne (broche ).
Schéma de l'exemple

entre la résistance de $10~k\Omega$ et le bouton-poussoir
sur l'autre coté du bouton-poussoir
relié à la résistance La broche D2 est utilisée en tant que broche d'interruption.
Code C++ basique
const uint8_t buttonPin = D2;
const uint8_t ledPin = D4;
volatile bool stateLed = false; //State of LED
//ISR = Interrupt Service Routine
void IRAM_ATTR blinkLed()
stateLed =! stateLed; //Swap led state
digitalWrite(ledPin, stateLed); //Update state
Serial.println("Changing led state");
void setup()
pinMode(ledPin, OUTPUT); //Set led on OUTPUT
attachInterrupt(digitalPinToInterrupt(buttonPin), blinkLed, RISING); //Start interrupt service
Serial.begin(9600);
void loop()
//Nothing in this loop...
Code C++ avancé
Dans l'exemple suivant, l'anti-rebond est fait de manière logicielle. [1]
Nous allons définir une durée pendant laquelle nous allons ignorer les fronts. Il s'agit de la période d'anti-rebond appelée DEBOUNCE\_TIME dans notre programme.
#define DEBOUNCE_TIME 200
le principe réside dans la lecture de la variable exprimant le temps passée depuis le démarrage de la carte.
La fonction millis() renvoie le temps écoulé en milliseconde depuis le démarrage.
Ainsi, au bout d'une seconde, milli() renvoie la valeur 10000...
A chaque appel de l'ISR, on va regarder si le temps depuis le dernier évènement est supérieur à
notre délai. Si c'est le cas, cela veut dire que nous pouvons mettre à jour l'état de la LED.
//Update
previousTime = currentTime;
currentTime = millis();
if(currentTime > (previousTime + DEBOUNCE_TIME) )
stateLed =! stateLed; //Swap led state
digitalWrite(ledPin, stateLed); //Update state
Serial.println("Changing led state");
Le code complet est le suivant :
#define DEBOUNCE_TIME 200 //'Anti-rebond'
const uint8_t buttonPin = D2;
const uint8_t ledPin = D4;
volatile bool stateLed = false; //State of LED
uint16_t currentTime = 0; //Current time
uint16_t previousTime = 0;
//ISR = Interrupt Service Routine
void IRAM_ATTR blinkLed()
{
//Update
previousTime = currentTime;
currentTime = millis();
if(currentTime > (previousTime + DEBOUNCE_TIME) )
stateLed =! stateLed; //Swap led state
digitalWrite(ledPin, stateLed); //Update state
Serial.println("Changing led state");
}
void setup()
pinMode(ledPin, OUTPUT); //Set led on OUTPUT
attachInterrupt(digitalPinToInterrupt(buttonPin), blinkLed, RISING); //Start interrupt service
Serial.begin(9600);
void loop()
//Nothing in this loop...
Si vous placer votre ISR après l'appel de la fonction attachInterrupt, vous aurez une erreur du compilateur car la fonction n'est pas déclarée (elle est juste définie).
Notes
Opposition à la méthode hardware, faite avec un condensateur et une résistance.
↑
[MCUQuiz]
Une interruption externe se déclenche 2 1 Via un appel de fonction 0 Via un évènement sur une broche 0 De manière aléatoire