Les INTERRUPTIONS





PRÉAMBULE
Lors de l'exécution d'un programme celui-ci effectue une quantité considérable d'instructions.

Si le programme principal doit interagir avec des évènements extérieurs, il le fait par exemple, grâce à des capteurs externes qui en fonction des informations recueillies sont transmises aux processeurs via ses broches d'entrées et sont ensuite traitées par le programme principal.

Pour que les informations de ces capteurs puissent interagir en temps réel avec le programme principal, il faut scruter en permanence les entrées du processeur pour saisir les moindres modifications envoyées par les capteurs.

Plus le nombre de capteurs ou d'éléments externes (clavier, interrupteur, bouton poussoir,...) est important, et plus la scrutation de ces éléments ralentit l'exécution du programme principal.

Dans une application ou la vitesse de traitement est importante cela est un handicap.

Il se peut même que dans certain cas la scrutation permanente des informations des capteurs soit inutile, par exemple dans le cas d'un capteur mesurant l'intensité de la lumière du jour, il est inutile de vérifier l'information de ce capteur en permanence, cela ne fait que ralentir l'exécution du programme principal.

Pour se libérer de ces contraintes et libérer le programme principal on a recours aux interruptions.

Grâce aux interruptions il n'est plus nécessaire de vérifier, scruter, en permanence les broches d'entrées reliées aux capteurs ce qui libère le programme principal de ces tâches.

Le rôle des interruptions est de faire surveiller les broches d'entrées par le processeur et d'informer le programme principal seulement en cas de modifications d'informations envoyées par un périphérique.

A partir du moment ou une interruption est détectée le programme principal s'interrompt, après avoir terminé l'exécution de l'instruction en cours, et exécute la routine d'interruption liées à la broche d'entrée correspondante c'est à dire à un périphérique précis.
Une fois la routine d'interruption exécutée le processeur revient à l'exécution du programme principal.
Ainsi le programme principal n'est pas ralenti par les périphériques externes et peut toujours interagir avec l'extérieur à tout moment seulement quand une nouvelle information est disponible.

Grâce aux interruptions les programmes deviennent beaucoup plus rapide et efficace.

principe execution interruption
Principe d'exécution d'une interruption
Les INTERRUPTIONS sur l'ARDUINO UNO
Un arduino uno est équipée d'un microcontrôleur Atméga 328P.

L'Atmega 328P possède 26 interruptions différentes qui peuvent être :
• Interne au microcontrôleur, par exemple le dépassement de la valeur maximale d'un compteur (Timer/compteur),
Externe au microcontrôleur, par exemple lorsqu'une broche d'entrée passe d'un niveau logique à un autre.
 
Chaque interruption ou vecteur d'interruption possède un niveau de priorité au sein du microcontrôleur.

niveau de priorite des interruptions
Niveau de priorité des interruptions

Lorsque plusieurs interruptions sont déclenchées en même temps, elles sont exécutées en fonction de leur niveau de priorité.
L'interruption possédant le numéro de vecteur le plus faible dispose de la priorité la plus haute et est exécutée la première.

Lorsqu'une interruption est déclenchée le programme principal est stoppé et la routine d'interruption ou ISR (Interrupt Service Routine) est déclenchée.
Comme le déroulement du programme principal est stoppé il faut veiller à ce que la routine d'interruption soit assez courte pour ne pas avoir trop impact sur le temps d'exécution du programme principal.

Lorsqu'une qu'un interruption est déclenché elle ne peut être interrompue par une autre interruption.
Le microcontrôleur ne prendra en compte cette nouvelle interruption que lorsque celle en cours sera terminé.

Les INTERRUPTIONS EXTERNES
Interruptions Externes PCINT0, PCINT1, PCINT2
Ces interruptions externes concernent les broches :
• 8 à 13 pour PCINT0,
• A0 à A5 pour PCINT1,
• 0 à 7 pour PCINT2.

Ces 3 vecteurs d'interruption s'appliquent pour un port complet :
PORT B pour les broches de 8 à 13 pour PCINT0,
PORT C pour les broches de A0 à A5 pour PCINT1,
PORT D pour les broches de 0 à 7 pour PCINT2.

Cela signifie qu'une interruption se déclenche si une quelconque des broches d'un port change d'état.
Pour ces trois vecteurs, l'interruption se déclenche à chaque changement d'état ( valeur logique d'une broche).

Comme une interruption sur une broche déclenche une interruption pour le port complet, il faut déterminer quelle est la broche qui a déclenché l'interruption.
Cette identification doit être prévue lors du développement du programme.

Interruptions Externes INT0, INT1
Comme vu précédemment ces deux interruptions font partie de PCINT2 puisque les broches 2 et 3 sont respectivement INT0 (PD2) et INT1 (PD1).

En complément de cela, les interruptions externes INT0 et INT1 possèdent chacune leur propre vecteur d'interruption.
C'est à dire que l'on peut les utiliser et les configurer séparément.

En utilisant les vecteurs d'interruption propres à INT0 et INT1 ont dispose de niveau de 2 déclenchements supplémentaires :
• Interruption sur détection d'un niveau bas (Low level),
   • Tant que le niveau sur la broche correspondante est bas il y aura exécution de la routine d'interruption,
• Interruption sur changement d'état (Any logical change),
   • L'interruption se déclenche à chaque fois que la broche change d'état : HIGH à LOW ou LOW à HIGH,
• Interruption sur front montant (Falling),
   • L'interruption se déclenche à chaque fois que la broche passe de LOW à HIGH,
• Interruption sur front descendant (Rising).
   • L'interruption se déclenche à chaque fois que la broche passe de HIGH à LOW.

Utilisation des interruptions externes
Les interruptions externes sont utilisées pour surveiller le changement d'état d'une broche et déclencher une interruption qui exécutera un code spécifique à cette interruption.

On peut grâce à ces interruptions surveiller :
• Le changement d'état d'une broche influencé par un capteur externe (détecteur de passage),
• Compter le nombre d'impulsion d'un dispositif extérieur,
• .....

Si l'on désire par exemple compter le nombre d'impulsion donnée par un dispositif externe, on branchera ce dispositif à une broche d'interruption convenablement paramétrée.

Comme le microcontrôleur possède en interne des timers/compteurs l'on pourra connaître par exemple la durée d'une impulsion générée par le dispositif externes en interrogeant le registre correspondant au timer/compteur utilisé.

C'est par exemple le principe utilisé pour compter la durée des impulsions en provenance d'une centrale DCC et détecter ainsi les bytes 0 ou 1.

L'interruption est appelée par l'instruction :
Pour l'INT0 :
ISR (INT0_vect) { code à effectuer } pour lNT0 broche 2 ou,
attachInterrupt (digitalPinToInterrupt(interruptPin), nom_de_la_routine, Type de déclenchement);

Pour l'INT1 :
• ISR (INT1_vect) { code à effectuer } pour lNT1 broche 3 ou,
attachInterrupt (digitalPinToInterrupt(interruptPin), nom_de_la_routine, Type de déclenchement);

Avec pour type de déclenchement :
LOW,
• CHANGE,
• RISING,
• FALLING.


Ces timers/compteurs peuvent également être utilisés pour déclencher des interruptions : Cela fait partie des Interruptions internes.
Les INTERRUPTIONS INTERNES
Comme on vient de l'aborder le microcontrôleur possède en interne des timers/compteurs qui fonctionnent :
• Au rythme de l'horloge du microcontrôleur,
    • Le rythme de l'horloge peut être divisé, le timer arrêté.
• Au rythme d'un signal extérieur,
• Au rythme d'une horloge extérieure. 

Ces timers/compteurs peuvent :
• Déclencher une interruption :
   • Soit en complément d'une interruption extérieure,
   • Soit par dépassement (OVERFLOW) des capacités de comptage du timer/compteur,
   • Soit par comparaison (COMPARAISON) avec d'autres registres du microcontrôleur.

• Générer un signal,
• Générer un signal PWM (Pulse Width Modulation),

• Mesurer avec une grande précision un intervalle de temps,
• Mesurer une fréquence.

schema general d'une interruption
Schéma général d'une interruption interne

L'Atméga 328 qui équipe l'arduino uno possède 3 timers/compteurs :
• Le TC0 est un timer/compteur de 8 bits qui compte jusqu'à 256 (0 à 255),
• Le TC1 est un timer/compteur de 16 bits qui compte jusqu'à 65536 (0 à 65535),
• Le TC2 est un timer/compteur de 8 bits qui compte jusqu'à 256 (0 à 255).

On peut représenter le compteur comme un escalier, à chaque top d'horloge l'on gravit une marche.

Le nombre de marche est imposé par la taille du registre utilisée :
TC0 : 256,
TC1 : 65536,
TC2 : 256.

compteur 8 bits
                  
compteur 16 bits
                                                                      
Compteur 8 bits
                                                                                                                    
Compteur 16 bits
L'horloge d'un arduino uno est de 16 Mhz. Cela vaut dire qu'un top d'horloge survient tous les 62,5 ns (nanoseconde) :

Ces temps sont extrêmement rapides et leur utilisation telle quelle peut avoir son utilité.

Pour revenir par exemple à l'utilisation de notre interruption dans le cas du clignotement d'une Led, ce temps est beaucoup trop rapide. Le changement d'état de la Led (allumage, extinction) interviendrait tous les :
• Pour le compteur 0 ou 2 : 62,5 ns * 256 = 16 µs. L'escalier est gravi en 16µs (62,5 Khz) et on observe que la Led est constamment allumée.
• Pour le compteur 1 : 62,5 ns * 65536 = 4,096 ms. L'escalier est gravi en 4,096 ms (244 Hz) et observe que la Led est constamment allumée.

duree compteur 8 bits
       
duree compteur 16 bits
                                                                          
Compteur 8 bits
                                                                                                                
Compteur 16 bits

Pour remédier à cela il faut ralentir l'horloge pour que l'escalier soit gravi plus lentement.

Pour ralentir le comptage et influer sur la durée d'un top d'horloge on ne peut pas ralentir l'horloge externe de l'arduino qui est réalisée par un quartz, mais dans le microcontrôleur il existe des registres internes au microcontrôleur qui vont nous permettre de diviser la fréquence de l'horloge et nous permettre de ralentir le temps de montée de l'escalier des compteurs.

Il faut déterminer la fréquence souhaitée ou le temps d'allumage et d'extinction voulue et ensuite paramétrer ces registres et le compteur pour obtenir la temporisation souhaitée.

Interruption par dépassement des capacités du compteur : OVERFLOW
Lorsque le compteur arrive en haut des marches il revient à 0.
Si l'on prend comme exemple le compteur 0 ou 2, en revenant à 0 (255 vers 0), il y a dépassement des limites du compteur. Cela vaut pour le compteur 1 avec un dépassement qui intervient de 65535 vers 0.
• Ce dépassement peut être utilisé pour générer une interruption par dépassement du compteur, on dit OVERFLOW,
• Ce dépassement est signalisé par un FLAG (drapeau) et une routine d'interruption peut être déclenchée à ce moment.

Cette surveillance de dépassement par overflow sert à compter le temps qui passe. Ainsi le clignotement d'une Led, plutôt que d'être utilisé par une instruction "DELAY" qui bloque le déroulement du programme pendant le délai déterminé, est réalisé par une interruption qui elle ne bloque pas le déroulement du programme.
Les choses se déroulent en parallèle : le microcontrôleur exécute le programme principal et dans le même temps surveille si une interruption survient.

Il faut bien sûr en fonction de la fréquence de clignotement souhaitée paramétrer correctement notre interruption.

L'interruption est appelée par l'instruction : ISR (TIMER2_OVF_vect) { code à exécuter } pour le timer 2.

Interruption par comparaison de la valeur du compteur : COMPARAISON
Pour le déclenchement d'une interruption à l'aide des compteurs, il n'est pas nécessaire d'attendre le débordement du compteur.

A chaque timer/compteur est associés deux registres de comparaison de taille identique.
On peut enregistrer une valeur dans ces registres qui est ensuite comparée en permanence avec la valeur du compteur.
En cas d'égalité une interruption ou un signal PWM (Pulse Width Modulation ou Modulation par Largeur d’Impulsion) peut être généré.

L'interruption est appelée par l'instruction :
• ISR (TIMER2_COMPA_vect) { code à exécuter } pour le timer 2.
• ISR (TIMER2_COMPB_vect) { code à exécuter } pour le timer 2.