Reklama

Základy ovládání mikrokontroléru ATmega(16/32) 6.díl – Externí přerušení

Úvod

  V tomto příspěvku si řekneme něco o externím přerušení. Pro ty, kteří se s tímto pojmem ještě nesetkali, se jedná o způsob přerušení aktuálního standardního běhu programu a možnost provedení okamžitě námi požadovaný kód. V praxi si to můžeme představit na příkladu puštěného hudebního přehrávače, který obsahuje jedno tlačítko na zapnutí a vypnutí zvuku. Konvenční metodou zjišťování stisknutí tlačítka podle návodu Základy ovládání mikrokontroléru Atmega 5.díl, bychom neustále ve funkci int main (void) zjišťovali stav tlačítka. To je ovšem nepraktické, pokud máme větší program, který je navíc náchylný na zpoždění, jako např. přehrávání zvuku, protože by bylo možné zjišťovat stav tlačítka pouze jednou za delší časový úsek. Uživatel by tak musel totiž držet tlačítko do doby, než se začne vykonávat funkce pro zjištění stisknutí tlačítka. Dále také uživatel nemá okamžitou zpětnou vazbu na stisk, což je velmi negativně vnímáno. Proto jsou mikrokontroléry opatřeny funkcí externího přerušení, kde na základě okamžitého stavu pinu mikrokontroléru je provedena rutina v obsluze přerušení. V našem případě by to bylo vypnutí zvuku u hudebního přehrávače.

Popis externího přerušení pro mikrokontrolér ATmega

 

Mikrokontrolér ATmega obsahuje tři externí přerušení a to: INT0 (pin PD2), INT1 (pin PD3) a INT2 (pin PB2). Vyvolat externí přerušení lze i pomocí pinu, který je konfigurován jako výstupní. Tímto je vytvořena možnost vyvolat softwarové přerušení přímo mikrokontrolérem. Při využívání externího přerušení jsou pro nás zajímavé registry SREG, GICR, MCUCR, MCUCSR a GIFR.

 

Prvním zmiňovaným registrem SREG musíme povolit možnost aktivace všech přerušení. Toho docílíme nastavením log. 1 sedmému tedy nejvyššímu bitu I.

 

Registrem GICR lze nastavovat povolení pro všechna tři externí přerušení INT0, INT1 a INT2.

Nastavením log. 1 sedmému bitu, tedy bitu s nejvyšší váhou povolujeme přerušení INT1, nastavením log. 1 šestému bitu povolíme přerušení INT0 a INT2 povolíme nastavením log. 1 pátému bitu. Zakázání přerušení provádíme nastavením stejných bitů, ale naopak do stavu log. 0. Přehled jednotlivých bitů pro povolení ukazuje následující tabulka Tab. 1.

Tab. 1: Popis bitů pro externí přerušení v registru GICR

Pozice bitu Povolení (1) / Zakázání (0) přerušení
7 – (nejvyšší váha) INT1
6 INT0
5 INT2

 

Dalším používaným registrem je registr GIFR. Tento registr obsahuje příznaky, které se používají pro vyvolání obsluhy přerušení. Pokud jsou povolena přerušení pomocí bitu SREG a také je povoleno žádané přerušení, běh programu se přesune do vektoru přerušení a vymaže se tento příznakový bit. Ručně lze tento bit vymazat zapsáním log. 1. Pokud je dané přerušení nastavené v režimu reakce na úroveň a ne hranu, je tento bit vždy vynulován. Platí, že bit INTF0 je použit pro INT0 atd. Přehled příznakových bitů ukazuje tabulka Tab. 2.

Tab. 2: Registr GIFR

Pozice bitu Požadavek pro:
7 – (nejvyšší váha) INTF1 pro INT1
6 INTF0 pro INT0
5 INTF2 pro INT2

 

Následovaný popis zahrnuje registr MCUCR. Tímto registrem vybíráme režim spouštění přerušení INT0 a INT1. Na výběr máme z režimů: spouštění při stavu log. 0, změny stavu, aktivace náběžnou hranou a aktivace sestupnou hranou. K výběru režimu slouží první čtyři bity registru MCUCR. Tabulka Tab. 3 ukazuje jednotlivé rozmístění bitů v registru MCUCR.

Tab. 3: Bity v registru MCUCR

Pozice bitu Označení
0 – (nejnižší váha) ISC00
1 ISC01
2 ISC10
3 ISC11

 

   Jednotlivé kombinace pro výběr režimu spouštění pro INT0 ukazuje tabulka Tab. 4.

Tab. 4: Režimy pro externí přerušení INT0

ISC01 ISC00 Režim
0 0

Reakce na stav log. 0

0 1

Reakce na jakoukoliv změnu stavu

1 0

Reakce na sestupnou hranu

1 1

Reakce na náběžnou hranu

 

  Jednotlivé kombinace pro výběr režimu spouštění pro INT1 ukazuje tabulka Tab. 5.

Tab. 5: Režimy pro externí přerušení INT1

ISC11 ISC10 Režim
0 0

Reakce na stav log. 0

0 1

Reakce na jakoukoliv změnu stavu

1 0

Reakce na sestupnou hranu

1 1

Reakce na náběžnou hranu

 

Pokud je vybrána reakce přerušení na úroveň log. 0, tak k přerušení bude docházet do té doby, dokud je na pinu stav log. 0. Navíc pokud dojde k vyvolání externího přerušení reagujícího na úroveň a zároveň je již například obsluhováno jiné přerušení, které zakázalo ostatní přerušení, tak pokud před dokončením předchozího přerušení již není stav pinu v log. 0, tak k vyvolání přerušení nedojde. Je to způsobené tím, že informace o vyvolání přerušení není uložena v registru GIFR.

 Pro režimy, kdy je nastavena reakce přerušení na hranu, platí, že délka impulsu musí být delší jak jedna perioda hodinového taktu. Pro režim přerušení, který reaguje na úroveň, musí tato úroveň trvat minimálně do doby, než dojde ke zpracování aktuální instrukce.

    Pro externí přerušení INT2 lze nastavit pouze citlivost na hranu. Toto lze provést pomocí šestého bitu ISC2 v registru MCUCSR. Při nastavení log. 1 je nastavena reakce na náběžnou hranu, zatímco nastavením log. 0 je nastavena reakce při sestupné hraně. Díky rozdílnému způsobu registrace přerušení INT2 oproti INT0 a INT1 může nastat při změně bitu ISCR2 falešná žádost na obsluhu přerušení, proto je vhodnější první zakázat přerušení v registr GICR poté vymazat příznak INTF2 zápisem log. 1 a až poté povolit přerušení pro INT2.

Vzorový příklad

   V našem vzorovém zdrojovém kódu budeme zobrazovat postupně čísla nula až devět pomocí sedmisegmentového displeje. Směr čítání nahoru, nebo dolů budeme určovat stisknutím tlačítka, které je umístěno na externím přerušením INT0. Problém, který musíme řešit, jsou opět zákmity na tlačítku. Pokud byste měli jako zdroj přerušení jiný obvod např. infračervený přijímač, nemuseli byste toto řešit, ale v našem případě použití mechanického tlačítka je to nutné. Zde tento problém osobně ošetřuji zakázáním přerušení v obsluze přerušení. Následné další povolení je až po vykonání potřebného zdrojového kódu, ale nesmíme zapomenout ještě před tím vynulovat příznak s požadavkem na další vybavení přerušení.S kombinací se zpožděním o minimální čas pro odeznění zákmitů se jedná o účinné ošetření. Pokud bychom zde použili klasickou metodu pro zjištění stisku tlačítka, museli bychom držet stisknuté tlačítko i více než 1 s po dobu dokončení zpoždění pro zobrazení číslice. To by bylo velmi nepraktické.

 

Okomentovaný zdrojový kód
 

001: #include <avr/io.h>// Vložení knihovny pro IO definice
002: #define F_CPU 16000000UL // Frekvence hodinového signálu (nutné pro delay.h)
003: #include <util/delay.h>// Hlavičkový soubor pro zpoždění
004: #include <avr/interrupt.h>// Hlavičkový soubor pro přerušení
005: #include <stdint.h>// knihovna pro standardní typy
006: // prototyp funkce
007: void switch_number(uint8_t show_number);
008:
009: volatile int direction;// Určuje přičítání / odečítání ,Volatile určuje
010: // kompilátoru, že se nemá snažit tuto
011: // proměnnou optimalizovat. Používá se
012: // především, pokud se může proměnná
013: // měnit v přerušení apod.
014:
015: ISR(INT0_vect)// Vektor přerušení pro INT0
016: {
017: GICR &= 0b10111111;// Nastavení zakázání přerušení pro INT0
018:
019: if (direction == 1)// Pokud je aktuální směr 1, změnit na 0
020: {
021: direction = 0;// Nastavení směru na čítání dolů
022: }
023: else// Pokud je aktuální směr 0, změnit na 1
024: {
025: direction = 1;// Nastavení směru na čítání nahoru
026: }
027: }
028:
029: int main(void)
030: {
031: int num = 0; // Proměnná pro aktuální číslo k zobrazení
032: int en_dis_int = 0; // Proměnná pro zjištění povolení nebo zakázání
033: // přerušení
034:
035: DDRA = 0xFF;// Nastavení PORTU A jako výstup
036: DDRD = 0x00;// Nastavení PORTU D jako vstup, INT0 se nachází na PD2
037: PORTD = 0xFF;// Nastavení pull up na PORTD
038: GICR |= 0b01000000;// Nastavení povolení přerušení pro INT0
039: MCUCR |= 0b00000010;// Nastavení reakce na sestupnou hranu pro INT0
040: PORTA = 0xFF;// Rozsvícení všech segmentů pro test, jestli jsou LED
041: // v pořádku
042:
043: _delay_ms(1000);// Zpoždění 1s
044:
045: sei();// Globální povolení přerušení pomocí registru SREG
046:
047: num = 0;// Aktuální číslo
048: direction = 1;// Čítání nahoru
049:
050: while(1)
051: {
052: if (direction == 1)// Pokud je směr 1, je přičítána 1
053: {
054: num++;// Inkrementace čísla
055:
056: if (num > 9)// Pokud je číslo větší jak 9, vynuluj číslo
057: {
058: num = 0;// Nastavení čísla na 0
059: }
060:
061: switch_number(num);// Zobrazení aktuálního čísla
062: }
063: else// Pokud je směr 0, je odečítána 1
064: {
065: num––;// Dekrementace čísla
066:
067: if (num < 0)// Pokud je číslo menší jak 0, přiřadit 9
068: {
069: num = 9;// Nastavení čísla 9
070: }
071:
072: switch_number(num);// Zobrazení aktuálního čísla
073: }
074: // Vymaskování registru GICR
075: en_dis_int = (GICR & 0b01000000);
076:
077: if (en_dis_int != 64)// Pokud není povoleno přerušení, tak jej povolíme
078: {
079: _delay_ms(150);// Minimální čas na odeznění zákmitů, pokud bychom byli již
080: // za zobrazením čísla – můžete měnit podle potřeby
081: GIFR |= 0b01000000;// Vymazání požadavku na přerušení
082: GICR |= 0b01000000;// Nastavení povolení přerušení pro INT0
083: }
084: }
085: return 0;
086: }
087:
088: // funkce pro zobrazení čísla
089: void switch_number(uint8_t show_number)
090: {
091: switch (show_number)
092: {
093: // rozsvícení čísla 0
094: case 0: PORTA = 0b00111111; break;
095: // rozsvícení čísla 1
096: case 1: PORTA = 0b00000110; break;
097: // rozsvícení čísla 2
098: case 2: PORTA = 0b01011011; break;
099: // rozsvícení čísla 3
100: case 3: PORTA = 0b01001111; break;
101: // rozsvícení čísla 4
102: case 4: PORTA = 0b01100110; break;
103: // rozsvícení čísla 5
104: case 5: PORTA = 0b01101101; break;
105: // rozsvícení čísla 6
106: case 6: PORTA = 0b01111101; break;
107: // rozsvícení čísla 7
108: case 7: PORTA = 0b00000111; break;
109: // rozsvícení čísla 8
110: case 8: PORTA = 0b01111111; break;
111: // rozsvícení čísla 9
112: case 9: PORTA = 0b01101111; break;
113: // rozsvícení čísla 0 při neshodě
114: default: PORTA = 0b00111111; break;
115: }
116: _delay_ms(1000);// Zastavení zobrazení na 1s
117: }

Vzorové zdrojové kódy slouží pouze k jednoduché demonstraci funkce, proto často obsahují globální proměnné, neobsahují většinou ukazatele, dále také neobsahují kontroly proměnných, definování nevyužitých pinů mikrokontroléru a podobné správné programátorské návyky. Proto je nutné tyto kódy brát s patřičnou rezervou.
 
Elektronické schéma obvodu

 

   Elektronické schéma zapojení ukazuje Obr. 1.

 

avr_6

Obr. 1: Elektronické schéma zapojení

Video s ukázkou funkce

[wpvp_flowplayer src=http://tajned.cz/wp-content/uploads/2013/11/video_AVR6.mp4 width=640 height=480 splash=http://tajned.cz/wp-content/uploads/2013/11/video_AVR6.png]

[1] ATMEL. 8-bit AVR Microcontroller with 16K Bytes In-System Programmable Flash. [online] citováno 3. Listopadu 2013. Dostupné na www: http://www.atmel.com/Images/doc2466.pdf

 
Aktualizace: 10.11.2015

Jiné příspěvky v kategorii:

 

Základy ovládání mikrokontroléru ATmega(16/32) 1.díl – První kroky

Základy ovládání mikrokontroléru ATmega(16/32) 2. díl – Kompilace a krokování programu

Základy ovládání mikrokontroléru ATmega(16/32) 3.díl – Nahrání vytvořeného zdrojového kódu do mikrokontroléru

Základy ovládání mikrokontroléru ATmega(16/32) 4.díl – Ovládání vstupně/výstupních portů

Základy ovládání mikrokontroléru ATmega(16/32) 5.díl – Ošetření zákmitů na vstupním pinu mikrokontroléru

Základy ovládání mikrokontroléru ATmega(16/32) 7. díl – Jednoduchá elektronická hrací kostka
Základy ovládání mikrokontroléru ATmega(16/32) 8.díl – A/D převodník (1.část)

Základy ovládání mikrokontroléru ATmega(16/32) 9.díl – A/D převodník (2.část)

Základy ovládání mikrokontroléru ATmega(16/32) 10.díl – A/D převodník (3.část)

Základy ovládání mikrokontroléru ATmega(16/32) 11.díl – Čítač / Časovač (1.část – Základní popis)

Základy ovládání mikrokontroléru ATmega(16/32) 12.díl – Čítač / Časovač (2.část – Popis registrů)

Základy ovládání mikrokontroléru ATmega(16/32) 13.díl – Čítač / Časovač (3.část – Praktická ukázka)

Základy ovládání mikrokontroléru ATmega(16/32) 14.díl – Dvouřádkový LCD displej

Základy ovládání mikrokontroléru ATmega(16/32) 15.díl – Popis implementace komunikace I2C a EEPROM paměti 24LC512

Základy ovládání mikrokontroléru ATmega(16/32) 16.díl – Watchdog

Základy ovládání mikrokontroléru ATmega(16/32) 17.díl – Obsluha maticové klávesnice

Základy ovládání mikrokontroléru ATmega(16/32) 18.díl – Jednotka USART (1. část – Popis)

Základy ovládání mikrokontroléru ATmega(16/32) 19.díl – Jednotka USART (2. část – Praktická ukázka)

Základy ovládání mikrokontroléru ATmega(16/32) 20. díl – Generování audio signálu pomocí PWM

Základy ovládání mikrokontroléru ATmega(16/32) 21. díl – Analogový komparátor

Základy ovládání mikrokontroléru ATmega(16/32) 22. díl – Krokování programu v jazyce symbolických adres (JSA)

 
Tajned facebook
 

Za případné chyby v textu, ve zdrojovém kódě, nebo ve schématickém zapojení se omlouváme.
AUTOŘI NEBEROU ŽÁDNOU ODPOVĚDNOST ZA PŘÍPADNÉ ÚJMY NA ZDRAVÍ ČI MAJETKU.