Logiciels > Programmation PIC > Bases > MP > Interruptions

Dernière mise à jour : 29/07/2009

Présentation

Les interruptions dans le domaine des microcontrôleurs ont pour moi bien longtemps constitué un grand mystère. Je comprenais que quelque chose se passait quand un évenement "externe" survenait, mais je ne comprenais pas comment exploiter cette information "subite". Il m'a fallu lire et décortiquer pas mal d'exemples pour en comprendre le principe général de fonctionnement. J'ai ainsi découvert qu'il existait des interruptions qui annonçaient un changement d'état sur une ligne d'entrée (un front montant par exemple), et des interruptions qui annonçaient le débordement d'un timer (réinitialisation d'un compteur après qu'il ait atteint sa limite de comptage maximale). Dans le premier cas, l'évenement est externe au PIC, il s'agit par exemple d'un état logique qui change sur une broche d'entrée / sortie configurée en entrée, et dans le second cas l'évènement est interne, il se produit à un instant donné dans le PIC lui-même.

Points communs...

Dans MikroPascal, il existe une routine spécifique pour la gestion des interruptions, qui s'appelle "Interrupt" et qui est unique. Elle peut être utilisée quelque soit le type d'interruption, c'est à dire quelque soit la cause (l'évènement) qui a crée l'interruption.

program electronique_pic_tuto_base_interrupt_001a;

procedure Interrupt;

begin
// action à exécuter lorsque l'interruption survient
end;

// main program
begin
Init;
while true do
begin
// code à exécuter "hors interruptions"
end;
end.


Comme plusieurs causes peuvent conduire à l'exécution de cette unique routine Interrupt, il convient, dans cette dernière même, de faire une "recherche sur la cause". Cela se fait simplement en analysant la valeur de "drapeaux" conçus pour cet usage et qui par leur valeur, indiquent si tel ou tel évenement est la cause de l'interruption. Prenons un exemple concret, basé sur le PIC 16F628A qui comporte plusieurs sources d'interruption. Ce microcontrôleur peut déclancher une interruption :
- quand une des broches du port B - configurées en entrées - change d'état logique;
- quand les timers internes TMR0 et TMR1 "débordent" (c'est à dire quand ils ont atteint leur compte maximal et qu'ils repassent à zéro);
- quand la sortie du comparateur interne change d'état;
- quand l'USART (module de réception de données série type RS232 ou MIDI) reçoit des données;
- et dans d'autres cas...
Pour que ces interruptions puissent déclancher la routine Interrupt, il faut les activer et savoir où aller lire leur cause. En d'autres termes, indiquer au microcontrôleur qu'on souhaite être informé quand elles surviennent. Pour cela, il existe plusieurs registres comportant plusieurs bits affectés à cette tâche : certains bits sont spécialement destinés à l'activation des interruptions, et d'autres bits sont destinés à stocker l'information qui dit que telle interruption a été provoquée. Par exemple, le timer TMR0 est capable de déclancher une interruption, si le bit qui permet de l'activer est correctement configuré. Ce bit est le bit N° 5 du registre INTCON, appelé aussi T0IE (Timer 0 Interrupt Enable). S'il est configuré à 1, l'interruption du timer 0 est activée, et s'il est configuré à 0, l'interruption du timer 0 est désactivée. En plus de ce bit d'activation T0IE, un autre bit est disponible, qui stocke le statut de l'interruption, il s'agit du bit  N° 2 du même registre INTCON, appelé T0IF (Timer 0 Interrupt Flag). Si la valeur de T0IF est à 0, cela signifie que le timer 0 n'a pas déclanché d'interruption. Et si la valeur de T0IF est à 1, cela signifie que le timer 0 a déclanché une interruption. Quand la routine Interrupt survient, il convient dans un premier temps de vérifier le statut des interruptions potentielles, c'est ce que montre l'exemple suivant.

procedure Interrupt;
begin
if INTCON.T0IF = 1 then
begin
// action à exécuter lorsque l'interruption du timer 0 survient
INTCON.T0IF := 0; // remise à zéro du statut de l'interruption
end;
end;


Remarques
- le bit du registre qui contient le statut de l'interruption (T0IF pour le timer 0) doit être remis à zéro par logiciel, de préférence dans la routine Interrupt même. Si cela n'est pas fait, aucune autre interruption de même type ne pourra avoir lieu par la suite.
- si un seul vecteur d'interruption est activé, il peut sembler inutile de chercher la cause du déclenchement de la routine Interrupt, puisque quand elle est déclanchée on en connait forcement la cause. Mais c'est un bon réflexe de vérifier l'origine de l'interruption, ne serait-ce que pour le cas où une autre est activée par inadvertance (je sais, ça ne peut pas arriver).

Si maintenant deux types d'interruptions sont déclanchées, par exemple celle du timer 0 et celle du changement d'état des entrées du port B, voici comment il faut procéder au niveau de la routine Interrupt.

procedure Interrupt;
begin
if INTCON.T0IF = 1 then
begin
// action N° 1, à exécuter lorsque l'interruption du timer 0 survient
INTCON.T0IF := 0; // remise à zéro du statut de l'interruption
end;
if INTCON.RBIF = 1 then
 begin
  // action N° 2, à exécuter lorsque l'interruption des entrées du port B survient
  INTCON.RBIF := 0; // remise à zéro du statut de l'interruption
 end;
end;


Et ne pas oublier, dans l'initialisation principale du logiciel, d'activer les interruptions que l'on souhaite surveiller, car dans le cas contraire on risque d'attendre longtemps l'appel de la routine Interrupt !

program electronique_pic_tuto_base_interrupt_001b;

procedure Init;
begin
 CMCON := %00000111; // comparators OFF
 TRISIO.0 := 0; // GPIO configuré en sortie
 ANSEL.ANS0 := 0; // GPIO configuré en sortie numérique
INTCON.GIE := 1; // activation générale (globale) des interruptions
INTCON.T0IE := 1; // activation interruption timer 0
INTCON.RBIE := 1; // activation interruption entrées port B
end;

procedure Interrupt;
begin
if INTCON.T0IF = 1 then
begin
// action N° 1, à exécuter lorsque l'interruption du timer 0 survient
INTCON.T0IF := 0; // remise à zéro du statut de l'interruption
end;
if INTCON.RBIF = 1 then
 begin
 // action N° 2, à exécuter lorsque l'interruption des entrées du port B survient
 INTCON.RBIF := 0; // remise à zéro du statut de l'interruption
 end;
end;

// main program
begin
Init;
while true do
begin
// code à exécuter "hors interruptions"
end;
end.


-