Sunteți pe pagina 1din 8

Circuite Programabile cu Aplicații în Biomedicină

Laborator 2

2. Întreruperile
2.1. Caracteristici generale

Scopul acestei lecții este familiarizarea studenților cu funcțiile de întreruperi externe ale
microcontrolerului.

Întreruperile într-un microcontroler sunt văzute ca niște evenimente speciale generate de


elementele periferice. Aceste evenimente pot fi reprezentate de apăsarea unui buton, atingerea unei
valori a numărătorului, terminarea de citit a unei valori a convertorului analog digital, etc. Toate
acestea sunt gestionate de un sistem intern numit sistem de întreruperi , sistem care are rolul de a
oferi procesorului informații referitoare la natura întreruperii și de a opri funcționarea ciclică tratând
întreruperea într-o rutină specială. Această rutină are o adresă specială de început.

Tratarea întreruperii are ca efect suspendarea firului normal de execuție al unui program și
lansarea în execuție a unei rutine de tratare a întreruperii (ISR: Interrupt Service Routine). Întreruperile
hardware au fost introduse pentru a se elimină buclele pe care un procesor ar trebui să le facă in
așteptarea unui eveniment de la un periferic. Folosind un sistem de întreruperi, perifericele pot
atenționa procesorul in momentul producerii unei întreruperi (IRQ: Interrupt request), 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. Înainte de a lansa în execuție o ISR, procesorul trebuie să aibă la dispoziție un mecanism
prin care să salveze starea în care se află în momentul apariției întreruperii. Aceasta se face prin
salvarea într-o memorie, de cele mai multe ori organizata sub forma unei stive, a registrului contor de
program (Program Counter), a registrelor de stare precum și a tuturor variabilelor din program care
sunt afectate de execuția ISR. La sfârșitul execuției ISR starea anterioară a registrelor este refăcută și
programul principal este reluat din punctul de unde a fost întrerupt.

Pentru a asocia o întrerupere cu o anumită rutină din program, procesorul folosește tabela
vectorilor de întrerupere. Fiecărei întreruperi îi este asociată o adresă la care programul va face salt în
cazul apariției acesteia. Aceste adrese sunt predefinite și sunt mapate in memoria de program într-un
spațiu continuu care alcătuiește tabela vectorilor de întrerupere. Adresele întreruperilor în tabela
vectorilor de întrerupere sunt setate în funcție de prioritatea lor, cu cât adresa este mai mică cu atât
prioritatea este mai mare. Pentru ATMega328, tabela vectorilor de întrerupere este dată în tabelul I.

Se observă că tabela vectorilor de întrerupere este plasată de la prima adresă a memoriei de


program și că întreruperile sunt puse din două în două adrese consecutive. Prioritatea cea mai mare o
are întreruperea de RESET, de la adresa 0, apoi întreruperea externa 0 (INT0). Perifericele care pot
genera întreruperi la ATMega328 sunt timerele, interfața seriala (USART), convertorul analog-digital
(ADC), controllerul de memorie EPROM, comparatorul analog si interfața seriala I2C.
Tabelul I. Tabela vectorilor de întrerupere

2.2. Butonul

De cele mai multe ori o întrerupere externă este activată de un buton. Un buton simplu este format
din două contacte metalice care se ating sub acțiunea utilizatorului. Aceste contacte metalice închid
circuitul și transmit unei componente electronice (în cele mai multe cazuri un microcontroler) starea
butonului. La apăsarea butonului apare fenomenul denumit „contact imperfect” (bouncing). Acesta se
manifestă prin oscilații electrice în schemă, de perioadă variabilă și pentru o durată de timp depinzând
de o serie de factori, cum ar fi: imperfecțiunile și impuritățile de pe suprafețele de contact, timpii de
răspuns ai materialelor, modul de încapsulare, puterea pe care o poate suporta suprafața de contact
ş.a. Pentru butonul folosit în cadrul laboratorului, această durată este în general mai mică de 10 ms.
Numai după această perioadă contactul realizat este sigur.

Deoarece aceste contacte imperfecte pot produce modificări însemnate în funcționarea normală
a schemei în care apar, este necesară eliminarea lor (debouncing). Acest lucru se poate realiza prin
metode hardware sau software. Butoanele pot transmite nivel de tensiune diferit, făcând ca sistemul
să fie binar, ON sau OFF. Astfel, aceste niveluri de tensiune (de exemplu, 5 volți = ridicat = ON = circuit
închis și 0 volți = scăzut = dezactivat = circuit deschis) ne ajută să reprezentăm logica binară de 0 și 1.
În Fig. 1 este reprezentat un exemplu de acest tip de circuit. În urma fluctuațiilor apărute la apăsarea
butonului, microcontrolerul poate înregistra mai multe apăsări și, într-un final, mai multe semnale de
0 și 1 consecutiv. Acest fenomen poate introduce erori în sistem. Pentru a menține tensiunea de ieșire
la un nivel constant 1 și pentru a nu apărea un scurt circuit la apăsarea butonului, se conectează o
rezistență de Pullup conform Fig. 1.
Figura 1. Schema electrică de acționare a unui buton și reprezentarea semnalului apărut la apăsarea acestuia

Prin implementare software, fenomenul de „bouncing” poate fi eliminat folosind diferiți


algoritmi și filtre. De exemplu, se poate introducere o întârziere sau se pot dezactiva întreruperile
pentru o perioada scurtă de timp după ce are loc primul contact. Totuși, aceste metode pot duce la
implementări ineficiente scăzând performanțele sistemului dacă nu sunt implementate corespunzător.

În categoria soluțiilor hardware, printre cele mai simple se regăsesc introducerea unui filtru
RC sau a unui circuit bistabil (CBB) tip R-S sau D.
Filtrele sunt circuite utilizate la prelucrarea semnalelor, prin care pot trece doar semnalele de
anumite frecvențe, impuse. În Fig. 2 este reprezentată schema electrică a unui circuit ce are
implementat un filtru trece jos format dintr-o rezistență și un condensator (R-C), cu scopul de a elimina
frecvențele înalte ale semnalului ce pot apărea în urma apăsării butonului. Pragul de filtrare se
numește frecvența de tăiere (fc) și este calculată conform formulei:
1
=
2
Semnalele cu frecvențe până la frecvența de tăiere sunt lăsate să treacă neatenuate, sau atenuate
foarte puțin, iar pe cele cu frecvențe superioare frecvenței de tăiere le atenuează foarte puternic.

Figura 2. Exemplu de implementare a unui filtru pentru eliminarea fluctuațiilor de semnal

De asemenea, există numeroase circuite integrate dedicate disponibile pe piață special realizate
pentru eliminarea fluctuațiilor de semnal (de ex. circuitul Trigger Schmitt).
2.3. Întreruperile externe în limbaj Arduino

Placa de dezvoltare Arduino are disponibili 2 pini pentru întreruperi externe: pinul 2 (PD2) și pinul 3
(PD3). O variantă de schema electrică de conectare a unui buton la un pin de întreruperi a plăcii de
dezvoltare Arduino este prezentată în Fig. 3. Este implementat astfel circuitul de tip RC prezentat în
Fig. 2. Folosind o rezistență R=4.7kΩ si un condensator C=0.1µF, rezultă o frecvență de tăiere de
aproximativ 338Hz. Rezistența de Pullup poate fi aleasă de ordinul kΩ, de exemplu Rp= 4.7kΩ.

Figura 3. Schema electrică de conectare a unui buton cu „debounce” la Arduino

Butonul are o schemă electrică conform Fig. 4. La apăsare, pinii 1 și 2 sunt conectați cu pinii 3 și 4.

Figura 4. Schema electrică buton

Din punct de vedere al sintaxei Arduino, cel mai uzual, întreruperile pot și activate folosind următoarea
funcție:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);

cu următorii parametrii:

pin: numărul pinului care este folosit pentru întrerupere (pentru Arduino UNO este pinul 2
sau pinul 3);
ISR: Interrupt Service Routine – numele funcției apelate care în momentul în care apare
întreruperea (această funcție nu are parametrii și nu returnează nimic);
mode: definește modul de activare a întreruperii astfel:
 LOW activează întreruperea când semnalul este 0 (low);
 CHANGE activează întreruperea când semnalul de la pin își schimbă valoarea (din 1 în
0 sau din 0 în 1)
 RISING activează întreruperea pe frontul crescător al semnalului (când semnalul pe la
pin se modifică din 0 în 1)
 FALLING activează întreruperea pe frontul descrescător al semnalului (când semnalul
pe la pin se modifică din 0 în 1)

Pentru dezactivarea întreruperilor se folosește funcția nointerrupts().

În exemplul de mai jos este activată o întrerupere folosind pinul 2 pe front crescător al
semnalului (la trecerea din 0 în 1). Funcția care se execută la activarea întreruperii poartă numele de
blink și schimbă valoarea parametrului stării LED-ului conectat la pinul 13.

volatile byte state = LOW; //definire variabilă pentru starea LED-ului

void setup() {
pinMode(13, OUTPUT); //setare direcție pin 13 - ieșire
pinMode(2, INPUT_PULLUP); //setare direcție pin 2 – intrare cu activare rezistență de Pullup

attachInterrupt(digitalPinToInterrupt(2), blink, RISING); //activare întrerupere


}

void loop() {
digitalWrite(13, state); //setare stare pin 13
}

void blink() { //funcția executată la activarea întreruperii


state = !state; //schimbarea valorii parametrului stării LED-ului
}

Exercițiul 1: Modificați circuitul astfel încât să își schimbe starea un LED conectat la pinul 13 atunci când
apare o întrerupere activată de un semnal cu front crescător.

Exercițiul 2: Modificați programul și circuitul astfel încât să își schimbe starea un LED conectat la pinul
10 atunci când apare o întrerupere activată de un semnal cu front descrescător.

În Fig. 5 este dat ca exemplu conectarea unui LED extern la pinul 13.

Figura 5. Schema electrică cu buton de activare a întreruperii și LED extern


2.4. Regiștrii microcontrolerului ATmeag328 de activare a întreruperilor externe

2.4.1. Activarea întreruperilor

Pentru a activa posibilitatea de a folosi întreruperile este utilizat registrul Status (SREG) prin setarea
bitului 7 (Global Interrupt Enable - I) cu valoarea 1. Dezactivarea întreruperilor se realizează prin
setarea acestui bit cu valoarea 0.

Figura 6. Registrul STATUS (SREG)

Pentru modificarea unui singur bit dintr-un registru se aplică operații logice (“SAU” sau “SI”) cu măști
de biți care să afecteze doar acel bit, prin schimbarea lui în 1 sau în 0 (0b1000000, respectiv
0b01111111).

De exemplu, schimbarea stării doar a bitului I din registrul SREG se poate face aplicând operația SAU (
| ) pe bit cu o mască de biți care are doar bitul 7 cu valoarea 1. Astfel, în registrul SREG bitul I va lua
valoarea 1 (“SAU” cu 1 rezultă 1), restul rămânând nemodificați (“SAU” cu 0):
SREG |= 0b10000000;

Întreruperile sunt activate setând registrul External Interrupt Mask Register (EIMSK).

Figura 7. Registrul EIMSK

Când bitul INT1 din EIMSK si bitul I din registrul SREG sunt setați 1, este activat pinul de întrerupere
extern. De asemenea, similar se procedează si pentru întreruperea INT0. Activitatea pe pini va
provoca o solicitare de întrerupere chiar dacă INT1 sau INT0 sunt configurați ca ieșire. Setarea biților
se realizează prin operații logice cu măști de biți.

Bit 1 – INT1: External Interrupt Request 1 Enable


Bit 0 – INT0: External Interrupt Request 0 Enable

2.4.2. Modul de activarea întreruperilor externe

Modul în care se activează întreruperilor externe se face cu ajutorul registrul External Interrupt
Control Register A (EICRA) care are forma din Fig. 7.

Figura 8. Registrul EICRA

Biții 3:2 – ISC1n: Interrupt Sense Control 1 [n = 1:0]


Întreruperea Externa 1 este activata de pinul extern INT1 daca fanionul I al registrului SREG si masca
de întrerupere corespunzătoare sunt setate. Nivelurile si fronturile pinului INT1 care activează
întreruperile sunt definite mai jos:

00 – un nivel LOW la INT1 generează o cerere de întrerupere ;


01 – orice schimbare logica la INT1 generează o cerere de întrerupere;
10 – frontul descrescător al INT1 generează o cerere de întrerupere;
11 - frontul crescător al INT1 generează o cerere de întrerupere;

Biții 1:0 – ISC0n: Interrupt Sense Control 0 [n = 1:0]

De asemenea, întreruperea Externa 0 este activata de pinul extern INT0 daca fanionul I al registrului
SREG si masca de întrerupere corespunzătoare sunt setate. Nivelurile si fronturile pinului INT0 care
activează întreruperile sunt definite mai jos:

00 – un nivel LOW la INT0 generează o cerere de întrerupere ;


01 – orice schimbare logica la INT0 generează o cerere de întrerupere;
10 – frontul descrescător al INT0 generează o cerere de întrerupere;
11 - frontul crescător al INT0 generează o cerere de întrerupere;

2.4.3. Regiștri fanion pentru întreruperi externe

Daca o cerere de întrerupere este activata pe un pin, registrul External Interrupt Flag (EIFR)
se modifica: bitul INTF0 sau INTF1 devin 1, in funcție de pinul folosit. Daca bitul I din SREG si bitul
INT0 sau INT1 din EIMSK sunt setați 1, microcontrolerul va sari la vectorul de întrerupere
corespondent. Iar fanionul din EIFR va fi resetat.

Figura 9. Registrul EIFR

2.4.4. Programarea în C a întreruperilor pe Arduino

În librăria Arduino, funcția attachInterrupt() are următoarea formă:


static void nothing(void) {
}
static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = {
nothing,
nothing,
};
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
intFunc[interruptNum] = userFunc;

switch (interruptNum) {
case 0:
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
break;
case 1:
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
break;
case 2:
break;
}
}
}
Se apelează practic regiștrii ce setează întreruperile. În exemplul de mai jos este implementat
programul de schimbare a stării LED-ului conectat la pinul 13 în urma activării pe front crescător a
întreruperii prin apăsarea butonului legat la pinul 2.
#include <avr/io.h>
#include <avr/interrupt.h>

volatile byte state = 0b00000000;//inițializare variabila stare LED

void setup() {
DDRD &= 0b11111011; //Setare pin întreruperi PD2 ca pin de intrare ~(1 << DDD2);
PORTD |= 0b00000100; //Activare rezistență de Pull-up (1 << PORTD2)

SREG |= 0b10000000; //Activare întreruperi

EICRA |= 0b00000011; //Setare mod întrerupere INT0 pe front descrescător;


EIMSK |= 0b00000001; //Activare întrerupere pe INT0 (1 << INT0);

DDRB = 0b00100000; //Setare pin PB5 ca pin de ieșire


PORTB &= 0b11011111; //Inițializarea stării pinului PB5 cu 0 (stingere LED conectat la pinul 13)
}

void loop() {
PORTB = state; //implementarea schimbării stării LED-ului conectat la PB5
}

ISR (INT0_vect) //funcția ce se execută la cererea de întrerupere (ISR)


{
state ^= 0b00100000; //operație XOR pentru schimbarea valorii bitului ce comanda PB5
}

Exercițiu: Modificați programul astfel încât să își schimbe starea un LED conectat la pinul 10 atunci când
apare o întrerupere activată de un semnal pe front descrescător pe pinul 3 al plăcii de dezvoltare
Arduino.

S-ar putea să vă placă și