2. diel - Prerušenie a časovač na module ESP-32
V predchádzajúcej lekcii, Zoznámenie s ESP-32 , sme sa zoznámili s čipom ESP-32 a vývojovou doskou ESP-32 DEVKIT DOIT.
V tomto tutoriále Internetu vecí s ESP32 sa zameriame na možnosti využitia prerušenia a časovania, ktoré nám modul ESP-32 ponúka. Vysvetlíme si princíp prerušenia a jeho dva typy.
Prerušenie
Prerušenia sú kľúčovým konceptom v oblasti mikrokontrolérov a
systémov vstavaných zariadení, ako je ESP32. Ako prerušenie označujeme
signály generované buď externými alebo internými
udalosťami. Tieto signály dočasne prerušia bežiaci program a
spustia špecifickú obslužnú rutinu. Uveďme si príklad s
jednoduchou LED diódou. Povedzme, že máme program, ktorý rozbliká LED.
Mikrokontrolér vykonáva všetky príkazy v programe tak, ako idú za sebou. Ak
však chceme monitorovať stav diódy v reálnom čase, narážame na
oneskorenie, ktoré je dané dĺžkou bežiaceho programu – pokiaľ
neskončí, nemáme možnosť do neho vstúpiť. A keď program beží v slučke
loop()
, sme od neho oddelení úplne. Tu do hry prichádza
prerušenie.
Pri prerušení mikrokontrolér zastaví beh programu a zavolá funkciu typu ISR (Interrupt Service Routine). Následne sa vykonajú všetky príkazy v tele funkcie a potom sa mikrokontrolér opäť vráti do hlavného programu. Tento mechanizmus umožňuje mikrokontroléru rýchlo reagovať na dôležité udalosti (ako je zmena stavu LED diódy) bez toho, aby bol nutný priebežný prieskum (polling) stavu diódy. To zefektívňuje použitie procesorového času a umožňuje mikrokontroléru zvládať viac úloh súbežne.
ESP-32 má celkom 32 prerušení na každé jadro a každé z nich má určitú prioritu.
Typy prerušenia
Základné rozdelenie je odvodené od zdroja prerušenia, delí sa preto na externé/hardvérové a softvérové .
Externé/hardvérové prerušenie
Toto prerušenie je vyvolané udalosťou na externú perifériu. Ako príklad si uveďme senzor dotyku. Pokiaľ senzor zaregistruje dotyk, zmení sa aj stav na GPIO a vyvolá sa prerušenie. Následne sa vykonajú príkazy v tele ISR funkcie a potom sa riadenie vráti do hlavného programu. Najväčšou výhodou prerušenia je, že nemusíme neustále monitorovať stav periférie. Periféria si naopak sama povie, že u nej nastala zmena, pre ktorú máme pripravenú obslužnú rutinu.
Softvérové prerušenie
Tento typ prerušenia nastane vo chvíli, keď program sám explicitne vyvolá prerušenie a určí rutinu, ktorá sa vykoná. Softvérové prerušenie sa často používa na manipuláciu s hardvérovými zariadeniami, signalizáciu chýb alebo na realizáciu komplexných funkcií v rámci operačného systému. Je možné ním tiež emulovať hardvérové udalosti pre testovanie alebo ladenie kódu, alebo vynútiť kontrolu niektorých funkcií.
Pri softvérových prerušeniach je dôležité zaistiť správnu synchronizáciu a riadenie prerušenia, aby nedochádzalo k nekonzistencii dát alebo iným problémom.
GPIO prerušenie
Výhodou modulu ESP-32 je, že všetky jeho GPIO piny je možné nakonfigurovať ako zdroje hardvérového prerušenia. Docielime to veľmi jednoducho, stačí iba príslušný pin pripojiť k zodpovedajúcej ISR. Toto nám umožní nasledujúce makro:
Makro obsahuje tri argumenty:
GPIOpin
: číslo pinu, ku ktorému má byť priradené prerušenie,ISR
: názov funkcie, ktorá má byť pri prerušení zavolaná,Event
: tretí argument určí, pri akej udalosti má byť prerušenie vyvolané. Možné hodnoty sú nasledovné:LOW
- prerušenie sa spustí, ak je na pine hodnotaLOW (0)
,HIGH
- prerušenie sa spustí, ak je na pine hodnotaHIGH (1)
,CHANGE
- prerušenie sa spustí vždy, keď sa na pine zmení hodnota (LOW
naHIGH
aleboHIGH
naLOW
),FALLING
- prerušenie sa spustí, ak sa hodnota na pine zmení zHIGH
naLOW
(dobežná hrana),RISING
- prerušenie sa spustí, ak sa hodnota na pine zmení zLOW
naHIGH
(nábežná hrana).
Po vykonaní tohto príkazu sa nám na piaty pin nastaví hardvérové prerušenie, ktoré spustíme napr. tlačidlom. Poďme si ešte popísať ISR funkciu, ktorá je odovzdávaná do makra ako argument:
Táto funkcia obsahuje
všetky príkazy, ktoré sa majú spustiť, keď je hlavný program prerušený.
Návratový typ funkcie IRAM_ATTR
zaistí, že bude funkcia
uložená do časti pamäte IRAM a nie do pamäte flash, čím zaistíme jej
rýchlejšie načítanie.
Keďže táto funkcia blokuje chod hlavného programu, je vhodné používať ju pre čo najkratšie úlohy.
Ako odstrániť prerušenie?
V niektorých prípadoch je potrebné odstrániť prerušenie na dobu
neurčitú. Na to nám poslúži funkcia detachInterrupt()
. Keďže
sme si v predchádzajúcom kroku nastavili prerušenie na pin 5
,
poďme ho teraz odstrániť:
Po vykonaní tohto príkazu
sa pin prestane chovať ako zdroj prerušenia do doby, kedy bude zavolaná
funkcia attachInterrupt()
alebo bude rebootovaný systém.
Praktický príklad - zhasnutie a rozsvietenie LED diódy
Teraz už vieme všetko, čo potrebujeme na vytvorenie jednoduchého programu, ktorý bude vďaka prerušeniu zhasínať a rozsvecovať LED. K tomuto príkladu budeme potrebovať okrem modulu aj tlačidlo a LED diódu, ktoré spoločne zapojíme podľa nasledujúcej schémy:
Všetko máme zapojené a môžeme sa vrhnúť na kód. Najskôr si nastavíme makrá pre jednotlivé piny a tiež definujeme ISR funkciu:
Pri využívaní prerušenia
v programe nie je potrebné definovať funkciu loop()
, tá teda
zostane prázdna. Zostáva už len doplniť telo funkcie setup()
, a
to nasledovne:
Pre úplnosť si zrekapitulujme celý program:
Teraz nám bude tlačidlo fungovať ako prepínač, tzn. že po jeho stlačení zmení hodnotu LED diódy na opačnú.
Časovanie
Keď už rozumieme tomu, čo je to prerušenie a ako funguje, môžeme sa pustiť do časovania. Časovanie je v podstate druh prerušenia, pretože generuje prerušenie po určitej časovej dobe. Často sa využíva napríklad ako počítadlo.
Časovanie na module ESP32
Náš mikrokontrolér ESP32 obsahuje dve skupiny časovačov, z ktorých každá skupina obsahuje dva hardvérové časovače. Každý časovač má 64 bitov. Tie sú založené na 16 bitovom prescaleri (delička vstupného signálu). Využívanie časovania je veľmi efektívne, pretože je pri ňom isté, že sa načasované udalosti stanú s presnosťou na milisekundu.
Všetky prerušenia vyvolané časovačom sa radia do softvérových prerušení.
Podľa frekvencie mikrokontroléra sa práve vďaka prescaleru táto frekvencia rozdelí na menšie celky, tzv. ticky. Nám už známa ISR funkcia sa teda vždy spustí po uplynutí určitého počtu tickov.
Poďme si teda zrekapitulovať, ako funguje časovač. Časovač používa počítadlo, ktoré sa zvýši o jedna vždy, keď uplynie určitý časový úsek (tick). Akonáhle bude počítadlo na hodnote, ktorú sme mu v kóde nastavili, časovač spustí prerušenie a počítadlo sa vynuluje.
Praktický príklad - pravidelné blikanie LED diódou
Predstavte si, že chceme každú sekundu bliknúť LED diódou. Ponúka sa
použiť funkciu delay()
, ale to by zabralo všetok procesorový
čas a nemohli by sme vykonávať žiadne iné úlohy. Lepšou cestou je teda
použitie časovača. Zapojenie pre tento príklad ponecháme v podstate
rovnaké, len z neho vymažeme tlačidlo. V kóde si najskôr zase nastavíme
hodnotu makra, vytvoríme premennú pre časovač a nadefinujeme si ISR
funkciu:
Do hodnoty makra je dôležité vložiť číslo pinu, do ktorého sme pripojili LED diódu. V prípade, že sa čísla nezhodujú, program nebude fungovať!
Keď máme všetko nastavené, doplníme už len telo funkcie
setup()
a máme hotovo. Funkcia loop()
zostane opäť
prázdna, pretože pre ukážku nepotrebujeme vykonávať iné operácie
(prerušenie nastane aj tak). Nastavíme pin LED diódy na výstup:
Následne zapneme časovač v
našom mikrokontroléri. Prvým parametrom funkcie je číslo
časovača, ktorý chceme použiť (hodnoty 0 až 3). Druhým
parametrom je hodnota prescalera, z ktorého sa počíta dĺžka jedného ticku.
My teraz použijeme hodnotu 80
. Tým dosiahneme frekvenciu 1 MHz,
čo znamená, že každý tick trvá jednu mikrosekundu. Posledný parameter
určuje, či má počítadlo počítať hore (true
) alebo dole
(false
):
Musíme tiež určiť, ktorá
funkcia sa má vykonať keď nastane prerušenie. V našom prípade využijeme
ISR funkciu naCas()
, ktorú sme si vytvorili:
Ďalej nastavíme interval
zmeny hodnoty na LED dióde. Na to použijeme funkciu
timerAlarmWrite()
. Prvý parameter určuje, o ktorý časovač sa
jedná, druhý určuje oneskorenie v mikrosekundách a tretí parameter
(true
) zaisťuje periodické resetovanie časovača:
A konečne len povolíme časovač a náš kód je pripravený na spustenie. Teraz bude LED dióda blikať vždy po jednej sekunde:
Na záver si ešte pre istotu zrekapitulujeme celý program:
V budúcej lekcii, Mód hlbokého spánku na module ESP-32 , si popíšeme mód hlbokého spánku na module ESP-32 a predvedieme si ho na praktickej ukážke.