Sistemul de Întreruperi

Să considerăm următorul exemplu: În clipa de față, task-ul meu principal este de a scrie la acest curs. Dacă în între timp fratele meu vine și îmi cere insistent să mă joc cu el, mă voi opri de la principala mea sarcină și îi voi acorda câteva minute (deci pot spune că mi-am suspendat task-ul curent și m-am dus să rezolv o problemă prioritară). În ciuda faptului că nu stau în permanență lângă fratele meu așteptând să-mi spună să mă joc cu el, sunt capabil să mă opresc de la ceea ce fac, să mă duc să mă joc, iar mai apoi să mă întorc de unde am rămas.

Așa funcționează și o întrerupere în cadrul unui sistem de calcul. Putem configura microcontrolerul astfel încât la detecția unui anumit eveniment (de exemplu, o schimbare de nivel logic pe un pin) să îndeplinească anumite sarcini, revenind mai apoi la ciclul normal de program. Astfel, întreruperea reprezintă suspendarea firului normal de execuție al unui program pentru rezolvarea unei probleme prioritare prin lansarea în execuție a unei rutine de tratare a întreruperii, rutină numită ISR (Interrupt Service Routine).

Cine poate genera întreruperile acestea? Ei bine, atât partea hardware cât și cea software. Întreruperile de tip hardware sunt generate ca și răspuns la un eveniment extern apărut, în timp ce întreruperile de tip software apar ca și răspuns la o comandă emisă în program. Sistemul de întreruperi hardware a fost introdus pentru a elimina buclele pe care un procesor trebuie să le facă în așteptarea unui eveniment de la un periferic (polling). Utilizând acest sistem, perifericele pot atenționa procesorul în momentul producerii unei întreruperi, acesta din urmă fiind liber să își ruleze programul normal în restul timpului și să își întrerupă execuția doar atunci când este necesar.

În simularea de mai jos sunt prezentate cele două cazuri: polling în partea stângă și întrerupere în partea dreaptă. În cazul polling-ului, CPU citește în permanență datele de pe pinul de intrare (GPIO), iar la trecerea lui în o logic va aprinde LED-ul atașat pe un alt pin. În celălalt caz, considerând că nivelul logic pe pinul de intrare este 1 logic (fiind legat direct la 5V), la apăsarea butonului acesta va trece în 0, generând o întrerupere externă (falling). Aici LED-ul va fi aprins cu ajutorul rutinei de tratare a intreruperii care tocmai a fost generată.

În cadrul microcontrolerelor pot exista mai multe surse de întrerupere, cele mai des întâlnite fiind cele externe. Pentru asocierea întreruperii cu o anumită rutină de program, procesorul folosește tabela vectorilor de întrerupere. Mai jos sunt prezentați câțiva vectori de întrerupere din cadrul microcontrolerului ATmega128A:

Număr vectorAdresăSursăDescriere întrerupere
2$0002INT0Întrerupere externă
3$0004INT1Întrerupere externă
10$0012TIMER2 COMPTimer/Counter 2 Compare match
11$0014TIMER2 OVFTimer/Counter 2 Overflow
18$0022SPI, STCSPI Serial Transfer Complet
22$002AADCADC Conversie Completă
33$0040USART1, TXUSART1 Transmisie Completă

Fiecare microcontroler are propria sa tabelă de vectori. De reținut aici este faptul că fiecărei întreruperi îi este asociată o adresă unică la care programul va face un salt în cazul apariției acesteia. Toate aceste adrese sunt predefinite și mapate în memoria de program. De asemenea, adresele sunt setate în funcție de prioritatea lor, prioritatea fiind mai mare cu cât adresa este mai mică. De exemplu, dacă presupunem că se generează o întrerupere externă pe pin și una de timer în același timp, mai întâi se tratează ISR-ul asociat întreruperii externe și mai apoi cel asociat întreruperii de timer.

După cum am prezentat în capitolul Porturi, fiecare pin de I/O poate avea mai multe funcționalități, printre aceste funcționalități regăsindu-se și întreruperile externe. Pentru a putea folosi pinii atașați microcontrolerului ca pini de întrerupere externă, trebuie să parcurgem următorii pași:

1. Consultăm foaia de catalog a microcontrolerului pentru a vedea ce pini suportă întreruperi externe.
Fiecare microcontroler dispune de o configurație diferită. De exemplu, placa de dezvoltare Arduino Uno (ce are la bază un ATmega328P), dispune de 2 pini de întrerupere externă, PORTD2 și PORTD3, asociați pinilor 2 și 3:

În comparație cu ATmega328P, ATmega128A dispune de 8 astfel de pini de întrerupere externă:

2. Activăm întreruperile externe pe pini prin setarea bitului 7 din registrul SREG.
Microcontrolerul este prevăzut cu un registru de status, SREG, registru ce conține infromații despre starea sistemului și rezultatul unor operații. De asemenea este utilizat pentru a modifica comportamentul programului sau pentru salturi condiționate. Foarte important aici este faptul că acest registru nu este salvat automat la apelul procedurilor sau la execuția întreruperilor.

Bit 7 – I: Activare întreruperi globale (Global Interrupt Enable)
Când acest bit este setat, întreruperile externe sunt activate. Dacă acest bit este setat pe nivel 0 logic, întreruperile externe sunt dezactivate. Bitul I poate fi setat în 1 sau 0 logic din software prin intermediul instrucțiunilor SEI și CLI. LA nivel hardware, este trecută în 0 logic automat la declanșareae întreruperii.

Având în vedere că restul biților nu sunt folosiți prea des, îi voi explica atunci când ne vom folosi de ei.

3. Setăm cei 3 regiștrii specifici întreruperilor externe, în funcție de preferințe.

EICRA – External Interrupt Control Register A

Acest registru este responsabil de controlul întreruperilor. Fiecare întrerupere dispune de 2 biți (ISCx1 și ISCx0, unde x reprezintă numărul întreruperii) ce definesc logica de generare a întreruperii. Se regăsesc aici 4 cazuri posibile
– 00: valoarea de LOW a pinului generează cererea de întrerupere;
– 01: orice schimbare a valorii logice a pinului generează cererea de întrerupere;
– 10: schimbarea din HIGH în LOW a valorii pinului generează cererea de întrerupere;
– 11: schimbarea din LOW în HIGH a valorii pinului generează cererea de întrerupere;

Comparativ cu ATmega328P care dispunde de doar 2 pini de întrerupere, microcontrolerul ATmega128A are în componența sa și regitrul EICRB, registru utilizat la setarea celorlalte 4 întreruperi externe (INT4, INT5, INT6, INT7). Registrul EICRB este identic ca funcționalitate cu registrul EICRA, singura diferență fiind legată de numărul întreruperilor pe care le setează.

EIMSK – External Interrupt Mask Register

Acest registru este utilizat la activarea sau dezactivarea măștii unuia dintre pinii INT7, INT6, …, INT0, pentru generarea de întreruperi. În momentul în care bitul 7 din registrul SREG și bitul corespunzător pinului de întrerupere externă este setat, întreruperea pe pin este activată. De reținut aici faptul că generarea întreruperii are în vedere setările efectuate în registrul anterior, EICRA. De exemplu, dacă bitul 7 din SREG și bitul INT7 din registrul EIMSK este setat, întreruperea pe pin este activă.

EIFR – External Interrupt Flag Register

Registrul EIFR este responsabil de înregistrarea apariției unei întreruperi. Fiecare bit din registru îi corespunde unui pin de întrerupere. Bitul poate fi șters (trecut în 0 logic) când ISR-ul asociat întreruperii generate a fost executat sau prin trecerea lui în 1 logic.

Design a site like this with WordPress.com
Get started