Popis funkcie prerušenia, práca s externým prerušením.
Prerušovací podsystém umožňuje efektívnu obsluhu nepravidelných udalostí, na ktoré má mikrokontrolér reagovať. V prípade výskytu definovanej udalosti mikokontrolér preruší beh programu a venuje sa programovej obsluhe udalosti, ktorá dané prerušenie vyvolala. Po skončení tejto programovej obsluhy mikrokontrolér pokračuje vo výkone hlavného programu. Význam prerušení je hlavne v zrýchlení a zefektívnení behu programu.
V jednej chvíli (t.j. v jednom strojovom cykle) sa môžu vyskytnúť viaceré prerušenia a mikrokontrolér musí rozhodnúť, ktorá žiadosť bude vykonaná ako prvá. Na to je potrebné definovať akési poradie dôležitosti – prioritu prerušení.
Na základe priority prerušení sa určí postupnosť spracovania žiadostí v tom istom strojovom cykle. Tabuľka zdrojov prerušení pre ATmega8 je uvedená na str.46. Platí teda, že čím menšie číslo vektora prerušenia, tým ma prerušenie vyššiu prioritu. Z tabuľky teda vidíme že najväčšiu prioritu ma prerušenie od RESET a najmenšiu od SPM_RDY.
Pred použitím akéhokoľvek prerušenia sa musia prerušenia najskôr globálne povoliť. To dosiahneme pomocou funkcie sei();
Naopak v niektorých kritických častiach programu chceme prerušenie globálne zakázať. Na to slúži funkcia cli();
Vidíme teda že ATmega8 má celkovo 19 zdrojov prerušenia. V tejto časti sa budeme venovať externým prerušeniam – INT0, INT1. Z využitým ďalších zdrojov prerušenia sa zoznámime v ďalších častiach seriálu.
Samotnú funkciu prerušenia potom deklarujeme takto:
ISR (vektor prerušenia) {
// … akcia prerušenia … //
}
Kompletný zoznam vektorov prerušenia pre C nájdete na adrese: https://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
Program s prerušením môže teda vyzerať takto:
// prerušenie od INT0
ISR (INT0_vect) {
// …nejaká akcia… //
}
int main () {
sei(); //povolenie globálneho prerušenia
GICR |= (1 << INT0); // povolenie prerušenia od INT0
while(1); // nekonečná slučka
}
Podľa možnosti sa snažíme obslužnú funkciu prerušenia spraviť čo najkratšiu (zmeniť premennú a pod.). Robíme to preto, aby zbytočne dlhá obsluha prerušenia nebrzdila hlavný program alebo prípadne ďalšie prerušenia, ktoré môžu nastať.
Zdielané premenné:
Ak potrebujeme v obsluhe prerušenia meniť hodnotu globálnej premennej, musí byť táto premenná deklarovaná s kľúčovým slovom volatile. V opačnom prípade sa zmena hodnoty premennej vykonaná v obsluhe prerušenia neuchová po skončení obsluhy. Príklad: volatile uint8_t abc;
MCUCR – pomocou bitov ISC11, ISC10, ISC01 a ISC00 v tomto registri nastavíme spôsob aktivácie externého prerušenia od INT0 a INT1.
Na výber máme tieto možnosti:
– Reakcia na nízku úroveň napätia na pine
– Zmena logického stavu na pine
– Reakcia na nábežnú hranu (rising edge)
– Reakcia na dobežnú hranu (falling edge)
Príklad:
Nastavíme reakciu INT0 na nábežnú hranu a INT1 na dobežnú hranu:
MCUCR |= (1 << ISC01) | (1 << ISC00) ; // INT0 na nábežnú hranu
MCUCR |= (1 << ISC11); //INT1 na dobežnú hranu
GICR – pomocou bitov INT1 a INT0 v tomto registri povolíme prerušenia od INT0 a INT1.
Príklad:
Povolenie prerušenia od INT1:
GICR |= (1 << INT1);
Zdrojový kód:
Zdrojový kód – použitie globálnej premennej:
To isté ako prvý ukážkový program, ale s použitím globálnej premennej. Tip: vyskúšajte si program bez kľúčového slova „volatile“.
volatile uint8_t led = 0;
ISR(INT0_vect) {
led = 1;
}
ISR(INT1_vect) {
led = 0;
}
int main() {
DDRD |= (1 << PD7); //PD7 ako výstupný (LED) // PD2,PD3 ako vstupné (ext. prerušenia) DDRD &= ~((1 << PD2) | (1 << PD3)); // Zapnutie interného pull-up rezistora PORTD |= (1 << PD2) | (1 << PD3); MCUCR |= (1 << ISC01); // dobežná hrana INT0 MCUCR |= (1 << ISC11); // dobežná hrana INT1 GICR |= (1 << INT1) | (1 << INT0); // povol prerušenia od INT1 a INT0 sei(); // globálne povolenie prerušení while(1) // nekonečný cyklus { if (led) PORTD |= (1 << PD7); // zapni LED else PORTD &= ~(1 << PD7); // vypni LED } return 0; }
Youtube video:
V ďalšej časti sa pozrieme na prácu s čítačom/časovačom a oboznámime sa s možnosťami jeho použitia.
Ďakujem za pomoc všetkým, čo sa podieľali na tvorbe tejto časti.
Prepáčte, ale pred zanechaním komentára sa musíte prihlásiť.
Zawin skvela praca 🙂 poznam dost ludi ktorym toto pomaha 🙂
skušal som to preložit aj bez toho kľúčového slova „volatile“. a preložilo mi to aj tak.toto bol ten tip?inak velmi dobry serial.teším sa na dalšiu časť.
a aj to fungovalo? 🙂
precitaj si este raz odsek „Zdielané premenné“
Ahojte,
Ak to spravne chapem tak pull-up nastavi na portX log. 1,
ale co sposobi, ze po stlaceni tlacidla dostavame log. 0?
Dakujem.
nastavi log1 ale cez napriklad 10K odpor.. a ked stlačiš tlačidlo tak to spojiš priamo s GND. Z toho vyplýva ze je tam ,,silnejšie,, GND ako 5V 😀 neviem ako ti to inak vysvetliť
Je pravda, že článek je již poněkud staršího data, ale pořád může pomoci těm, kteří začínají.
Jenže !!! NIKDY !!!! nepřipojujte LED diodu bez ochranného odporu !!!!!