Voilà un chapitre qui fera certainement peur à beaucoup de futurs programmeurs.
Pourtant, le mécanisme des interruptions est très aisé à comprendre, et également à
mettre en uvre, pour autant que lon travaille de manière propre et
structurée.
12.1 Quest-ce quune interruption ? |
Imaginez une conversation normale. Chaque interlocuteur prend la parole quand vient son
tour de parler. Survient alors un événement extérieur dont le traitement est urgent.
Par exemple, un piano tombe du 3ème étage de limmeuble au pied duquel
vous discutez. Vous imaginez bien que votre interlocuteur ne va pas attendre la fin de
votre phrase pour vous signaler le danger. Il va donc vous INTERROMPRE durant le cours
normal de votre conversation., afin de pouvoir TRAITER IMMEDIATEMENT lEVENEMENT
extérieur. Les interlocuteurs reprendront leur conversation où elle en était arrivée,
sitôt le danger écarté.
Et bien, pour les programmes, cest exactement le même principe. Votre programme
se déroule normalement. Survient un événement spécifique. Le programme principal est
interrompu (donc, subit une INTERRUPTION), et va traiter lévénement, avant de
reprendre le programme principal à lendroit où il avait été interrompu.
Linterruption est donc une RUPTURE DE SEQUENCE ASYNCHRONE, cest à dire non
synchronisée avec le déroulement normal du programme.
Vous voyez ici lopposition avec les ruptures de séquences synchrones,
provoquées par le programme lui-même (goto, call, btfss
).
12.2 Mécanisme général dune interruption |
Nous pouvons dire, sans nous tromper de beaucoup, quune routine
dinterruption est un sous-programme particulier, déclenché par lapparition
dun événement spécifique. Cela a lair un peu ardu, mais vous allez voir que
cest très simple.
Voici donc comment cela fonctionne :
- Le programme se déroule normalement
- Lévénement survient
- Le programme achève linstruction en cours de traitement
- Le programme saute à ladresse de traitement de linterruption
- Le programme traite linterruption
- Le programme saute à linstruction qui suit la dernière exécutée dans le
programme principal.
Il va bien sûr de soi que nimporte quel événement ne peut pas déclencher une
interruption. Il faut que 2 conditions principales soient remplies :
- Lévénement en question doit figurer dans la liste des événements susceptibles
de provoquer une interruption pour le processeur sur lequel on travaille
- Lutilisateur doit avoir autoriser linterruption, cest à dire doit
avoir signalé que lévénement en question devait générer une interruption.
Organigramme général de lexécution dune interruption :
Que pouvons-nous dire en voyant cet ordinogramme ? Et bien, nous pouvons déjà
nous dire que le programme principal ne sait pas quand il est interrompu, il est donc
crucial de lui remettre ses registres dans létat où ils étaient avant
linterruption.
En effet, supposons que linstruction xxx ait positionné un flag (par exemple, le
bit dindicateur Z). Si par malheur, la routine dinterruption a modifié ce
bit, le programme ne pourra pas se poursuivre normalement.
Nous voyons également que linstruction xxx termine son exécution avant de se
brancher sur la routine dinterruption. Une instruction commencée nest donc
jamais interrompue.
12.3 Mécanisme dinterruption sur les PICs |
Bien entendu, les PICs répondent au fonctionnement général ci-dessus, mais elles ont
également leurs particularités. Voyons maintenant le principe des interruptions sur les
PICs
- Tout dabord, ladresse de début de toute interruption est fixe. Il
sagit toujours de ladresse 0x04. Toute interruption provoquera le saut du
programme vers cette adresse.
- Toutes les sources dinterruption arrivant à cette adresse, si le programmeur
utilise plusieurs sources dinterruptions, il lui faudra déterminer lui-même
laquelle il est en train de traiter.
- Les PICs en se connectant à cette adresse, ne sauvent rien automatiquement, hormis le
contenu du PC, qui servira à connaître ladresse du retour de linterruption.
Cest donc à lutilisateur de se charger des sauvegardes.
- Le contenu du PC est sauvé sur la pile interne (8 niveaux). Donc, si vous utilisez des
interruption, vous ne disposez plus que de 7 niveaux dimbrication pour vos
sous-programmes. Moins si vous utilisez des sous-programmes dans vos interruption.
- Le temps de réaction dune interruption est calculé de la manière suivante : le
cycle courant de l'instruction est terminé, le flag d'interruption est lu au début du
cycle suivant. Celui-ci est achevé, puis le processeur s'arrête un cycle pour charger
l'adresse 0x04 dans PC. Le processeur se connecte alors à l'adresse 0x04 où il lui
faudra un cycle supplémentaire pour charger l'instruction à exécuter. Le temps mort
total sera donc compris entre 3 et 4 cycles.
- Une interruption ne peut pas être interrompue par une autre interruption. Les
interruptions sont donc invalidées automatiquement lors du saut à ladresse 0x04
par leffacement du bit GIE (que nous allons voir).
- Les interruptions sont remises en service automatiquement lors du retour de
linterruption. Linstruction RETFIE agit donc exactement comme
linstruction RETURN, mais elle repositionne en même temps le bit GIE.
Les interruptions sur les PICs :
12.4 Les sources dinterruptions de la 16F84 |
La 16F84 est très pauvre à ce niveau, puisquelle ne dispose que de 4 sources
dinterruptions possibles (contre 13 pour la 16F876 par exemple). Les événements
susceptibles de déclencher une interruption sont les suivants :
- TMR0 : Débordement du timer0 (tmr0). Une fois que le contenu du tmr0 passe de 0xff
à 0x00, une interruption peut être générée. Nous utiliserons ces propriétés dans le
chapitre sur le timer 0.
- EEPROM : cette interruption peut être générée lorsque lécriture dans une
case EEPROM interne est terminée. Nous verrons ce cas dans le chapitre sur
lécriture en zone eeprom.
- RB0/INT : Une interruption peut être générée lorsque, la pin RB0, encore
appelée INTerrupt pin, étant configurée en entrée, le niveau qui est appliqué est
modifié. Nous allons étudier ce cas ici.
- PORTB : De la même manière, une interruption peut être générée lors du
changement dun niveau sur une des pins RB4 à RB7. Il nest pas possible de
limiter linterruption à une seule de ces pins. Linterruption sera effective
pour les 4 pins ou pour aucune.
12.5 Les dispositifs mis en uvre |
Comment interdire ou autoriser les interruptions, comment détecter quel est
lévènenement déclencheur, et comment les gérer ? Nous allons aborder ceci
dabord de manière symbolique, pour vous aider à bien visualiser la procédure.
Imaginons un hôtel. Le groom de service représente notre programme. Lhôtel
comporte 4 chambres, et chaque chambre est équipée dun bouton-poussoir. Chaque
bouton-poussoir servant à appeler le groom, est relié à une lampe à laccueil de
lhôtel.
Chaque lampe a la possibilité de faire résonner une sonnette si linterrupteur
général de la sonnette est positionné, et si linterrupteur particulier reliant
chaque lampe à la sonnette est mis.
Voilà donc le schéma obtenu (attention, cest un schéma symbolique, pas
électrique).
Quand vous comprendrez bien ce petit schéma symboliques, vous aurez compris les
interruptions. Vous voyez tout de suite quil y a deux méthodes pour que le groom
soit prévenu.
Soit via la lampe, soit via la sonnette.
- Pour la première méthode, le groom doit venir voir les lampes à intervalles
réguliers pour vérifier si personne na appelé. Il doit donc venir SCRUTER le
tableau de signalisation. Cest la méthode de SCRUTATION.
- Avec la sonnette, le groom est INTERROMPU dans son travail par celle-ci. Il na pas
besoin de venir scruter inutilement, mais il sera dérangé dans son travail par la
sonnette. Cest la méthode des INTERRUPTIONS Notez déjà les points suivants :
- Le locataire de la chambre ne peut décider quelle méthode utilisée, cest le
groom qui décide de valider ou non les sonnettes.
- Le groom peut inhiber toutes les sonnettes en une seule fois, ou décider quelle chambre
va pouvoir actionner la sonnette.
- Les interrupteurs de validation nagissent pas sur les lampes.
- Si le groom est interrompu dans son travail par la sonnette, il doit de toute façon
aller regarder les lampes pour voir qui a sonné. Sauf sil sait quil na
autorisé quune seule chambre à actionner la sonnette.
- Ce qui napparaît pas sur ce schéma simplifié, mais quil faut savoir,
cest que, une fois la lampe allumée, elle le reste. Cest le groom qui doit
léteindre manuellement.
Appliquons donc tout ceci en pratique sur la 16F84. Vous avez déjà compris que lampes
et interrupteurs étaient, dans la 16F84, des bits de registres particuliers. Voici
maintenant le registre principal de gestion des interruptions pour la 16F84.
12.6 Le registre INTCON (INTerrupt CONtrol) |
Ce registre se situe à ladresse 0x0B, dans les 2 banques. Il est donc toujours
accessible. Il est détaillé figure 4-5 page 16. Cest un registre de bits, donc,
chaque bit a une fonction particulière. Voici le détail de ces bits :
b7 : GIE
Global Interrupt Enable bit. Il permet de valider ou dinvalider toutes les
interruptions dune seule fois. Ce bit correspond donc à notre interrupteur de
validation générale.
b6 : EEIE
Eeprom write complete Interrupt Enable bit. Ce bit permet de valider
linterruption de fin décriture en eeprom (nous étudierons plus tard le
mécanisme décriture eeprom).
b5 : T0IE
Tmr0 Interrupt Enable bit : Valide linterruption générée par le
débordement du timer0.
b4 : INTE
INTerrupt pin Enable bit : Valide linterruption dans le cas dune
modification de niveau de la pin RB0.
ATTENTION : rappelez-vous le bit 6 du registre OPTION, qui détermine quel est le
sens de transition qui provoque linterruption. On pourra donc choisir si cest
une transition 0->1 ou 1->0 qui provoque linterruption, mais pas les deux
ensemble.
b3 : RBIE
RB port change Interrupt Enable bit : Valide les interruptions si on a changement
de niveau sur une des entrées RB4 à RB7.
b2 : T0IF
Tmr0 Interrupt Flag bit. Cest un Flag, donc il signale. Ici cest le
débordement du timer0
b1 : INTF
INTerrupt pin Flag bit : signale une transition sur la pin RB0 dans le sens
déterminé par INTEDG du registre OPTION (b6)
b0 : RBIF
Port Interrupt Flag bit : signale quune des entrées RB4 à RB7 a été
modifiée.
Remarque
Rappelez-vous que les flags ne se remettent pas à 0 tout seuls. Cest votre
programme qui doit sen charger, sous peine de rester indéfiniment bloqué dans une
routine dinterruption. Nous dirons que ces flags sont des FLAGS REMANENTS
Remarquez déjà que tous les bits dont le nom se termine par E (Enable) sont en fait
des commutateurs de validation (ce sont les interrupteurs de notre schéma symbolique).
Les bits donc le nom se termine par F sont des Flags (indicateurs). Ils sont représentés
par des lampes sur notre schéma symbolique. Sur celui-ci nous avons 5 interrupteurs et 4
ampoules. Or nous navons que 8 bits dans INTCON0. Que nous manque-t-il ?
Si vous regardez attentivement, il nous manque le bit EEIF. Mais, rassurez-vous, ce bit
existe bien, il est tout simplement dans le registre EECON1, que nous verrons dans la
leçon sur les accès EEPROM. Nous allons donc transformer notre schéma symbolique pour
quil corresponde à la réalité dune PIC16F84.
Après ces explications détaillées, trop diront les habitués des processeurs, vous
devez maintenant avoir compris le fonctionnement des interruptions sur la 16F84. Analysons
maintenant quelques points de la routine dinterruption en elle-même. Pour rester
concrets, nous allons mélanger théorie et pratique.
12.7 Sauvegarde et restauration de lenvironnement |
Si vous regardez de nouveau lorganigramme de la routine dinterruption, vous
constatez que vous devez procéder à la sauvegarde et à la restauration de
lenvironnement de votre programme. En quoi cela consiste-t-il ?
Et bien, comme nous lavons déjà dit, votre programme interrompu ne sait pas
quil la été, donc vous devez remettre les registres qui permettent à votre
programme principal de fonctionner dans létat où ils étaient au moment de
linterruption.
Petit exemple :
Supposons votre programme principal interrompu entre les 2 instructions
suivantes :
|
Movf |
mavariable , w |
; charger mavariable et positionner Z |
|
Btfss |
STATUS , Z |
; tester bit Z et sauter si vaut 1 |
Il est plus que probable que votre routine dinterruption va utiliser au moins une
instructions qui modifie le bit Z. Vous devrez donc restaurer le registre STATUS dans
létat quil était avant de sortir de la routine dinterruption. Sinon le
test ne se fera pas sur la valeur de mavariable, mais sur une valeur de Z modifiée par la
routine dinterruption. De plus, il est à peut prêt certain que w va être modifié
également, donc à sauvegarder.
12.7.1 Les registres à sauvegarder
Et bien, le PC est sauvegardé automatiquement, le programme revient donc à la bonne
adresse tout seul. STATUS est, comme nous venons de voir, à restaurer par la routine
dinterruption.
Si, dans la routine dinterruption et dans le programme principal, nous utilisons
ladressage indirect, nous devrons également restaurer FSR.
W sera également modifié par la routine dinterruption. Sil y a
dautres registres à sauvegarder, ce sera en fonction du fonctionnement de votre
programme. Les seuls registres à sauver obligatoirement sont donc STATUS et W.
12.7.2 La méthode de sauvegarde
En voilà une bête question, allez-vous vous dire. En effet, avec un simple :
|
movf |
STATUS , w |
; charge STATUS dans W |
|
movwf |
emplacement_de_sauvegarde |
; sauvegarde STATUS |
Les registres semblent sauvegardés.
Et bien, analysons en détail ce qui ce passe dans ce cas. Si on analyse le
fonctionnement de movf, nous constatons que le bit Z est affecté par cette opération.
Donc, dans W nous navons plus STATUS tel quil était, mais déjà un status
modifié. Nous ne pouvons donc pas utiliser cette procédure. Mais alors, comment
faire ?
Il suffit de réfléchir : Le problème est damener STATUS dans le registre
W SANS AFFECTER aucun bit de STATUS. Il suffit de chercher une instruction qui pourrait
convenir. Pourquoi pas linstruction swap ? Pour rappel, cette instruction
inverse les 4 bits de poids faibles avec les 4 bits de poids forts de loctet
désigné .
Effectuons donc la sauvegarde de la manière suivante :
|
swapf |
STATUS , w |
; swap status avec résultat dans w sans rien modifier |
|
movwf |
status_temp |
; sauver status swappé dans variable de sauvegarde |
Pour restaurer, il faudra donc " reswapper " status_temp avant de
le remettre dans STATUS.
Donc, nous pourrons utiliser la procédure suivante :
|
swapf |
status_temp , w |
; swap ancien status, résultat dans w |
|
movwf |
STATUS |
; restaurer status |
En effet, movwf ne modifie aucun bit du registre STATUS, swapf remet dans lordre
status_temp et place le résultat dans w. constatons cependant que cette procédure à
linconvénient de modifier à chaque fois le registre W. Nous devrons donc sauver W
AVANT de sauver STATUS (sans modifier STATUS pas encore sauvé), et nous devrons restaurer
W APRES avoir restauré STATUS (et de nouveau sans modifier STATUS déjà restauré)
Pour sauver W, pas de problème, linstruction suivante :
|
movwf |
w_temp |
; sauver registre W |
Sauve W sans modifier STATUS.
Par contre, pour restaurer W, nous devons charger w_temp SANS MODIFIER STATUS, il nous
faut donc de nouveau utiliser swap. Seulement, nous avions sauvé w non
" swappé ". Pour le restaurer, nous ne devons pas le
" swapper ", ce qui peut aussi se traduire par le
" swapper " 2 fois. Nous pouvons donc écrire :
|
swapf |
w_temp,f |
; Swapper w_temp sans modifier Z |
|
swapf |
w_temp,w |
;Swapper une deuxième fois w_temp, résultat dans w, STATUS |
|
|
|
; non affecté |
La première instruction " swappe " lancienne valeur de w et
place le résultat dans lemplacement de sauvegarde. La seconde instruction
" swappe " une seconde fois cette valeur, et place le résultat dans
W. Nous avons donc rechargé W sans modifier STATUS.
Voici donc la structure de base dune routine dinterruption :
;********************************************************************** |
; ROUTINE INTERRUPTION |
;********************************************************************** |
|
|
|
|
|
|
;sauvegarder registres |
|
|
;-------------------------- |
|
org |
0x004 |
; adresse d'interruption |
|
movwf |
w_temp |
; sauver registre W |
|
swapf |
STATUS , w |
; swap status avec résultat dans w |
|
movwf |
status_temp |
; sauver status swappé |
|
|
|
|
|
; switch vers différentes interrupts |
|
|
; ---------------------------------------- |
; ici, on teste éventuellement de quelle interruption il
sagit |
|
|
|
|
|
|
; traitement des interruptions |
|
|
; ---------------------------------- |
; ici, on peut traiter interruption puis effacer son flag |
|
|
|
|
|
|
;restaurer registres |
|
|
;---------------------- |
|
swapf |
status_temp,w |
; swap ancien status, résultat dans w |
|
movwf |
STATUS |
; restaurer status |
|
swapf |
w_temp,f |
; Inversion L et H de l'ancien W |
|
|
|
; sans modifier Z |
|
swapf |
w_temp,w |
; Ré-inversion de L et H dans W |
|
|
|
; W restauré sans modifier status |
|
retfie |
|
; return from interrupt |
Et voilà votre squelette de routine dinterruption : vraiment pas
compliqué, nest-ce pas ? Il ny a plus quà compléter, car le
fichier m16F84.asm contient déjà les routines de sauvegarde et restauration (que nous
venons dexpliquer) et les tests de type dinterruption (que nous allons
détailler).
Comme je suis partisan de la programmation structurée, la routine de switch branche en
réalité sur des sous-programmes séparés. Rien nempêche en effet dutiliser
des sous-programmes dans une routine dinterruption.
12.7.3 Particulatité de linstruction " RETFIE "
A ce niveau de lexposé, une remarque pertinente serait la suivante :
Pourquoi existe-t-il une instruction RETFIE, alors quon pourrait utiliser
RETURN ?
Et bien, vous ne pouvez pas interrompre une interruption par une autre. Si
cétait le cas, les sauvegardes des registres W et STATUS seraient
" écrasé " par une seconde opération (mais cest possible sur
dautres processeurs). Donc, dès que le programme est branché sur
linterruption, le bit GIE est mis à 0 automatiquement.
Pour quune nouvelle interruption puisse avoir lieu une fois celle en cours
terminée, il faut remettre GIE à 1. Ceci est exécuté automatiquement par RETFIE.
Vous allez alors me dire : et si je fais ceci ?
|
bsf |
INTCON , GIE |
; remettre GIE à 1 |
|
RETURN |
|
; et sortir de la routine dinterruption |
Et bien, cest exactement ce que fait RETFIE, mais à un détail près, et ce
détail est de la plus grande importance : RETFIE est une seule et même instruction,
donc ne peut pas être interrompue par une interruption.
Dans le cas où les 2 instructions précédentes seraient utilisées, une fois GIE mis
à un, si un des flags dinterruption est toujours à 1 (autre interruption, où la
même qui se reproduit une autre fois), le programme se reconnecterait sur la routine
dinterruption avant davoir exécuté le RETURN, donc avant davoir
restauré le PC.
Celui-ci continuerait à occuper un emplacement sur la pile. En sachant que la pile est
limitée à 8 emplacements, il y aurait de nombreuses chances de plantage du programme par
débordement de la pile.
|