|
2.6 Întreruperi
Întreruperile sunt un mecanism a unui microcontroler ce îi permit să
răspundă la unele evenimente la momentul când se întâmplă, indiferent de
ce face atunci microcontrolerul. Aceasta este o parte foarte importantă,
pentru că permite conexiunea microcontrolerului cu lumea de afară. În
general, fiecare întrerupere schimbă debitul programului, îl întrerupe şi
după executarea unui subprogram (rutine de întrerupere), continuă din
acelaşi punct.

Registrul
de control al unei întreruperi se numeşte INTCON şi se găseşte la adresa
0Bh. Rolul lui este de a permite sau interzice cererile de întreruperi, şi
în caz că nu sunt permise, înregistrează cererile de întrerupere singulare
prin biţii lui.
Registru INTCON

bit 0
RBIF (RB Port Change Interrupt Flag bit-bit Steguleţ de Întrerupere
a Schimbării Portului RB) Bit ce informează despre schimbările de la pinii
4, 5, 6 şi 7 ai portului B.
1=cel puţin un pin şi-a schimbat starea
0=nu s-a întâmplat nici o schimbare la vreun pin
bit 1 INTF (INT External Interrupt Flag bit-bit Steguleţ de
Întrerupere Externă INT) A avut loc o întrerupere externă.
1=a avut loc o întrerupere
0=nu a avut loc o întrerupere
Dacă s-a detectat un front crescător sau descrescător la pinul RB0/INT,
(ce este definit cu bitul INTEDG în registrul OPTION), bitul INTF este
setat. Bitul trebuie să fie şters în subprogramul întrerupere pentru a
detecta următoarea întrerupere.
bit 2 T0IF (TMR0 Overflow Interrupt Flag bit-bit Steguleţ
Depăşire Întrerupere TMRO) Depăşirea contorului TMRO.
1=contorul şi-a schimbat starea de la FFh la 00h.
0=depăşirea nu a avut loc
Bitul trebuie să fie şters în program pentru ca o întrerupere să fie
detectată.
bit 3 RBIE (RB port change Interrupt Enable bit-bit Permite
Întreruperea schimbării portului RB) Permite să aibă loc întreruperi la
schimbarea stării pinilor 4, 5, 6, şi 7 ai portului B.
1=permite întreruperi la schimbarea stării
0=întreruperi interzise la schimbarea stării
Dacă RBIE şi RBIF au fost simultan setate, va avea loc o întrerupere.
bit 4 INTE (INT External Interrupt Enable bit-bit Permite
Întrerupere externă INT) Bit ce permite întreruperea externă de la pinul
RB0/INT.
1=întrerupere externă permisă
0=întrerupere externă interzisă
Dacă INTE şi INTF au fost setate simultan, va avea loc o întrerupere.
bit 5 T0IE (TMR0 Overflow Interrupt Enable bit-bit Permite
Depăşire Întrerupere TMRO) Bit ce permite întreruperile în timpul
depăşirii contorului TMRO.
1=întrerupere permisă
0=întrerupere interzisă
Dacă T0IE şi T0IF au fost simultan setate, va avea loc întreruperea.
Bit 6 EEIE (EEPROM Write Complete Interrupt Enable bit-bit
Permite Întrerupere Completă a Scrierii EEPROM) Bit ce permite o
întrerupere la sfârşitul unei rutine de scriere în EEPROM
1= întrerupere permisă
0= întrerupere interzisă
Dacă EEIE şi EEIF (ce este în registrul EECON1) au fost simultan setate,
va avea loc o întrerupere.
Bit 7 GIE (Global Interrupt Enable bit-bit Permite
Întrerupere Globală) Bit ce permite sau interzice toate întreruperile.
1=toate întreruperile sunt permise
0=toate întreruperile sunt interzise
PIC16F84 are patru surse de întrerupere:
1. Terminarea scrierii datelor în EEPROM
2. Întrerupere TMR0 cauzată de depăşirea timer-ului
3. Întrerupere în timpul schimbării la pinii RB4, RB5, RB6 şi RB7 ai
portului B.
4. Întrerupere Externă de la pinul RB0/INT al microcontrolerului
În general, fiecare sursă de întrerupere are doi biţi legaţi la ea. Unul
permite întreruperea, iar celălalt detectează când au loc întreruperi.
Există un bit comun numit GIE ce poate fi folosit pentru a interzice sau
permite toate întreruperile simultan. Acest bit este foarte folositor când
se scrie un program pentru că permite ca toate întreruperile să fie
interzise pentru o perioadă de timp, aşa ca execuţia unei părţi importante
a programului să nu fie întreruptă. Când instrucţiunea ce resetează bitul
GIE a fost executată (GIE=0, toate întreruperile interzise), fiecare
întrerupere ce rămâne nerezolvată trebuie ignorată.

Întreruperile ce rămân nerezolvate şi ce au fost ignorate, sunt procesate
când bitul GIE (GIE=1, toate întreruperile sunt permise) va fi şters. Când
i s-a răspuns întreruperii, bitul GIE a fost şters, aşa că orice
întreruperi adiţionale vor fi interzise, adresa de întoarcere a fost
trimisă în stivă, iar adresa 0004h a fost scrisă în contorul programului –
numai după aceasta începe răspunsul la o întrerupere! După ce este
procesată întreruperea, bitul a cărui setare a cauzat o întrerupere
trebuie şters, sau rutina de întrerupere va fi procesată automat tot mereu
în timpul întoarcerii la programul principal.
Păstrarea conţinutului regiştrilor importanţi
Doar valoarea de întoarcere a contorului programului este înmagazinată
într-o stivă în timpul unei întreruperi (prin valoare de întoarcere a
contorului programului înţelegem adresa instrucţiunii ce trebuie
executată, dar nu a fost executată pentru că a avut loc întreruperea).
Păstrând doar valoarea contorului programului adesea nu este suficient.
Unii regiştri ce sunt în uz în programul principal pot fi de asemenea în
uz în rutina de întrerupere. Dacă ei nu sunt reţinuţi, programul principal
va obţine valori complet diferite în acei regiştri în timpul întoarcerii
dintr-o rutină de întrerupere, ceea ce va cauza erori în program. Un
exemplu de asemenea caz este conţinutul registrului de lucru W. Dacă
presupunem că programul principal a folosit registrul de lucru W pentru
unele din operaţiile sale, şi că a păstrat în el o valoare ce este
importantă pentru următoarea instrucţiune, atunci o întrerupere ce se va
întâmpla înainte de acea instrucţiune va schimba valoarea registrului de
lucru W, ce va influenţa direct programul principal.
Procedura de înregistrare de regiştri importanţi înainte de a merge la o
rutină de întrerupere se numeşte PUSH, în timp ce procedura ce aduce
valorile înregistrate înapoi, se numeşte POP. PUSH şi POP sunt
instrucţiuni ale altor microcontrolere (Intel), dar sunt atât de larg
acceptate că o întreagă operaţie este numită după ele. PIC16F84 nu are
instrucţiuni ca PUSH şi POP, şi ele trebuie să fie programate.

Datorită
simplităţii şi folosirii frecvente, aceste părţi ale programului pot fi
făcute ca macro-uri. Conceptul unui Macro este explicat în "Limbaj de
asamblare program". În următorul exemplu, conţinuturile regiştrilor W şi
STATUS sunt memorate în variabilele W_TEMP şi STATUS_TEMP înainte de
rutina de întrerupere. La începutul rutinei PUSH trebuie să verificăm
bancul selectat în prezent pentru că W_TEMP and STATUS_TEMP nu se găsesc
în bancul 0. Pentru schimbul de date între aceşti regiştri, instrucţiunea
SWAPF se foloseşte în loc de MOVF pentru că nu afectează starea biţilor
registrului STATUS.
Exemplul este un program asamblor pentru următorii paşi :
1. Testarea bancului curent
2. Stocarea registrului W indiferent de bancul curent
3. Stocarea registrul STATUS în bancul 0
4. Executarea rutinei de întrerupere pentru procesul de întrerupere (ISR)
5. Restaurează registrul STATUS
6. Restaurează registrul W
Dacă mai sunt şi alte variabile sau regiştri ce trebuie stocaţi, atunci ei
trebuie să fie păstraţi după stocarea registrului STATUS (pasul 3), şi
aduşi înapoi înainte ca registrul STATUS să fie restaurat (pasul 5).
Acelaşi
exemplu se poate realiza utilizând macro-uri, făcând astfel programul mai
eligibil. Macro-urile ce sunt deja definite, pot fi folosite pentru
scrierea de noi macro-uri. Macro-urile BANK1 şi BANK0 ce sunt explicate în
capitolul "Organizarea memoriei" sunt folosite cu macro-urile 'push' şi
'pop'.
Întrerupere externă la pinul RB0/INT al microcontrolerului
Întreruperea externă la pinul RB0/INT este triggerată de frontul crescător
(dacă bitul INTEDG=1 în registrul OPTION<6>), sau de frontul descrescător
(dacă INTEDG=0). Când apare semnalul corect la pinul INT, bitul INTF este
setat la registrul INTCON. Bitul INTF (INTCON<1>) trebuie resetat în
rutina de întrerupere, aşa ca întreruperea să nu aibă loc din nou în
timpul întoarcerii la programul principal. Acesta este un pas important al
programului pe care programatorul nu trebuie să-l uite, sau programul va
merge constant în rutina de întrerupere. Întreruperea poate fi închisă
prin resetarea bitului de control INTE (INTCON<4>).
Întreruperea în timpul depăşirii contorului TMRO
Depăşirea contorului TMRO (de la FFh la 00h) va seta bitul T0IF
(INTCON<2>). Aceasta este o întrerupere foarte importantă pentru că multe
probleme reale se por rezolva folosind această întrerupere. Unul din
exemple este măsurarea timpului. Dacă ştim cât timp are nevoie contorul
pentru a completa un ciclu de la 00h to FFh, atunci numărul de întreruperi
înmulţit cu acea durată de timp va da timpul total scurs. În rutina de
întrerupere unele variabile vor fi incrementate în memoria RAM, valoarea
acelei variabile înmulţite cu timpul de care are nevoie contorul pentru a
contoriza într-un ciclu întreg, va da timpul total scurs. Întreruperea
poate fi pornită/oprită prin setarea/resetarea bitului T0IE (INTCON<5>).
Întrerupere pe timpul unei schimbări la pinii 4, 5, 6 şi 7 ai portului B
Schimbarea semnalului de intrare la PORTB <7:4> setează bitul RBIF
(INTCON<0>). Patru pini RB7, RB6, RB5 şi RB4 ai portului B, pot triggera o
întrerupere ce are loc când starea la ei se schimbă de la unu la zero
logic, sau viceversa. Pentru ca pinii să fie sensibili la această
schimbare, trebuie definiţi ca intrare. Dacă oricare din ei este definit
ca ieşire, întreruperea nu va fi generată la schimbarea stării. Dacă ei
sunt definiţi ca intrare, starea lor curentă este comparată cu vechea
valoare ce a fost stocată la ultima citire de la portul B. Întreruperea
poate fi pornită/oprită prin setarea/resetarea bitului RBIE în registrul
INTCON.
Întreruperea la terminarea subrutinei write în EEPROM
Această întrerupere este doar de natură practică. Pentru că scrierea
într-o locaţie EEPROM durează cam 10ms (care este o durată lungă în
termenii microcontrolerului), nu este rentabil de a aştepta până la capăt
scrierea. Este adăugat astfel mecanismul de întrerupere ceea ce permite
microcontrolerului să continue executarea programului principal, în timp
ce scrierea în EEPROM este făcută în plan secundar. Când scrierea este
terminată, întreruperea informează microcontrolerul că scrierea s-a
terminat. Bitul EEIF, prin care se face această informare, se găseşte în
registrul EECON1. Producerea unei întreruperi poate fi interzisă prin
resetarea bitului EEIE în registrul INTCON.
Iniţializarea întreruperii
Pentru a folosi un mecanism de întrerupere a unui microcontroler, trebuie
făcute unele sarcini pregătitoare. Aceste proceduri sunt pe scurt numite
"iniţializare". Prin iniţializare definim la ce va răspunde
microcontrolerul, şi ce va ignora. Dacă nu setăm bitul ce permite o
anumită întrerupere, programul nu va executa un subprogram întrerupere.
Prin aceasta putem obţine controlul asupra producerii întreruperii, ceea
ce este foarte folositor.

Exemplul
de mai sus arată iniţializarea unei întreruperi externe la pinul RB0 al
microcontrolerului. Unde se vede unu setat, înseamnă că întreruperea este
permisă. Producerea altor întreruperi nu este permisă, şi toate
întreruperile împreună sunt interzise până ce bitul GIE este ţinut în unu.
Următorul exemplu arată o cale tipică de a dirija întreruperile. PIC16F84
are doar o locaţie unde adresa unui subprogram întrerupere este memorată.
Aceasta înseamnă că mai întâi trebuie să detectăm ce întrerupere este la
îndemână (dacă mai mult de o sursă de întreruperi este disponibilă), şi
apoi putem executa acea parte a programului ce se referă la acea
întrerupere.

|

|
Reîntoarcerea dintr-o rutină de întrerupere poate fi făcută cu
instrucţiunile RETURN, RETLW şi RETFIE. Se recomandă ca să fie utilizată
instrucţiunea RETFIE pentru că acea instrucţiune este singura ce setează
automat bitul GIE, ceea ce permite să se producă o nouă întrerupere. |
|