Interrupts
interrupts, polling, ISR, low power, sleep mode
Introduction: Indiana Jones and the Golden Idol
(slide) Verím, že Indiana Jonesa predstavovať netreba. Vo svojom prvom filmovom príbehu sa na začiatku filmu nachádza časť, v ktorej sa snaží získať artefakt s názvom Golden Idol. Ten sa nachádza na bezpečnostnom mechanizme, ktorý sa snaží Indy “hacknúť”.
(slide) Pôvodná elektrická schéma tohto pekelného zabezpečovacieho systému sa síce nedochovala, ale schéma jej repliky realizovaná s doskou Arduino UNO vyzerá nasledovne:
A kód pre mikrokontrolér vyzerá zasa takto:
void lockdown(){ .println("Running all the booby-traps"); Serial.println("Close the cave entrance"); Serial(0); exit} int main(){ (); init // setup .begin(9600); Serial(2, INPUT); pinMode // loop for(;;){ if(digitalRead(2) == LOW){ .println("Silence..."); Serial(1000); delay}else{ .println("Intruder detected"); Serial.println("Lockdown initiated."); Serial(); lockdown} } }
Ak sa na ten kód pozrieme pozorne, tak nám musí byť jasné, prečo Indiana Jones tak váhal a dal si záležať na rýchlosti výmeny artefaktu Golden Idol: čas, ktorý mal na výmenu, trval len 1s!
Čo to znamená, že mal čas len 1s? Prečo nie viac a prečo nie menej? Ako pomôcť Hovitským programátorom lepšie zabezpečiť svoj bezpečnostný mechanizmus postavený na doske (nie len) Arduino UNO?
Blocking Function Call
(slide) Funkciu
delay()
radíme medzi tzv. blokujúce funkcie. Obecne môžeme povedať, že blokujúce volanie je taký typ volania, ktoré pozastaví vykonávanie ďalšieho kódu programu, pokiaľ sa toto volanie neukončí. Napr. môže ísť o čakanie ne odpoveď zo vzdialeného servera alebo o výsledok dlhotrvajúceho výpočtu.To isté platí aj pre funkciu
delay()
. Táto funkcia pozastaví vykonávanie programu na uvedený čas v milisekundách. Podľa dokumentácie však má niekoľko výnimiek: zaznamenanie prichádzajúcej sériovej komunikácie, zachovanie úrovní pinov (ako digitálnych, tak aj PWM) a fungujú prerušenia.Takže ak sa pozrieme do skeču, je nám jasné, že Indiana Jones má na výmenu práve 1s, na ktorú sa vykonávanie celého programu pozastaví.
Takže - koľko času stačí? Bude systém bezpečnejší, keď čas bude kratší? Ušetrím viac energie, keď bude čas dlhší? Koľko je teda dosť? A neviem zareagovať okamžite po stlačení?
The Polling
Ešte predtým, ako sa pohneme ďalej, pomenujeme jeden prístup, ktorý bol v uvedenom fragmente kódu objavený. Okrem toho sa s ním môžete bežne stretnúť v mnohých ďalších programoch. Priblížme si ho drobnou ilustráciou.
(slide) Pamätáte sa na druhú časť animáku Shrek? Shrek šiel spolu s Fionou a oslíkom na návštevu k Fioniným rodičom do kráľovstva za siedmymi horami a siedmymi dolinami. A pamätáte sa na to, čo robil celý čas oslík? Celý čas sa pýtal rovnakú otázku: “Kedy tam už budeme?”
A presne rovnaký prístup zvolili aj autori predmetného zabezpečovacieho systému. A rovnaký spôsob sme zvolili aj v prípade čítania hodnoty z LDR a PIR senzorov v prípade nášho nočného svetla. A to v pravidelných 1s intervaloch.
(slide) Pri získavaní hodnôt z týchto senzorov sa správame presne tak, ako oslík v Shrekovi - neustále sa pýtame na tú istú vec. Znova a znova. Vo svete informatiky sa tento prístup nazýva slovom polling, pretože sa vo veľkom pýtame (z angl. poll). Jeho princíp spočíva v neustálom dopytovaní sa externého zariadenia, či na ňom nedošlo k požadovanej udalosti, resp. k zmene stavu. Polling predstavuje synchrónnu operáciu.
Polling je veľmi jednoduchý a častokrát postačuje pre riešenie väčšiny problémov. Má však aj niektoré nevýhody. Jednou z nich je vysoká pravdepodobnosť straty údajov. K tomu môže dôjsť napr. vtedy, ak externé zariadenie pošle údaje mikrokontroléru tesne potom, ako sa ich ten pokúsil prečítať. Alebo aj vtedy, ak dôjde k pohybu uprostred 500 ms prestávky a počas tých istých 500 ms sa pohyb aj skončí.
Samozrejme existujú požiadavky, pri ktorých je takéto správanie postačujúce. Napr. merať vonkajšiu teplotu stačí v niekoľkominútových pravidelných intervaloch a prípadný výkyv teplôt medzi dvoma meraniami je možné považovať za zanedbateľný.
Vďaka neustálemu dopytovaniu sa si polling vyžaduje vyhradenie väčšieho množstva zdrojov a hlavne času mikrokontroléra. Ten teda miesto vykonávania potrebných operácií plytvá svojimi zdrojmi na neustále kontrolovanie stavu externého zariadenia. To sa priamoúmerne dokáže prejaviť na spotrebe energie, pretože čím častejšie kontrolujeme stav externého zariadenia, tým viac energie spotrebujeme.
The Interrupts
Ako teda zabezpečiť, aby mikrokontrolér ošetril vzniknutú udalosť v momente, keď k nej dôjde bez akéhokoľvek spozdenia? A je to vôbec možné?
(slide) Zareagovať okamžite v prípade zmeny úrovne signálu na pine mikrokontroléra, môžeme pomocou prerušenia (z angl. interrupt). Koncept prerušení je vo svete mikrokontrolérov veľmi dôležitý.
Prerušenie je mechanizmus, ktorým dá prostredie mikrokontroléru vedieť, že sa práve stalo niečo dôležité. Vo všeobecnosti je možné povedať, že prerušenie je špeciálny signál pre mikrokontrolér, ktorý poslal softvér alebo hardvér a vyžaduje si okamžitú pozornosť.
Výhodou takéhoto prístupu je vo všeobecnosti zníženie zaťaženia mikrokontroléra, ktorý nemusí stále dookola testovať, či k udalosti došlo alebo ešte nie (viď polling). V porovnaní s polling-om má prerušenie lepší reakčný čas, pretože reaguje na udalosť okamžite.
Princíp prerušenia sa využíva aj v architektúre riadenej udalosťami (a zngl. event driven architecture) alebo v programovaní riadenom udalosťami (z angl. event driven programming). V objektovom programovaní je zasa tento prístup opísaný pomocou návrhového vzoru pozorovateľ (z angl. observer).
Podobne, ako keď donášková služba volá priamo zákazníkovi, aby ho informovala o tom, že je donáška pripravená, aj požiadavku o prerušenie dostane od zariadenia priamo mikrokontrolér Tým pádom môže prísť požiadavka o prerušenie kedykoľvek a prerušenie predstavuje asynchrónny spôsob komunikácie.
Hlavný rozdiel medzi polling-om a prerušením je v tom, či sa softvér sám opýta alebo hardvér sám oznámi, či došlo k predmetnej udalosti.
Interrupt Service Routine
(slide) Inštrukcie programu, ktorý beží v mikrokontroléri, sa (obyčajne) vykonávajú sekvenčne. To znamená, že po vykonaní jednej inštrukcie sa vykoná nasledujúca inštrukcia v poradí. Akonáhle však mikrokontrolér dostane požiadavku na prerušenie, pozastaví sa vykonávanie inštrukcií programu mikrokontroléra a ten spustí špeciálnu funkciu na spracovanie prerušenia, ktorá sa označuje ISR (z angli. Interrupt Service Routine). Po jej skončení sa obnoví vykonávanie prerušeného programu vykonaním ďalšej inštrukcie v poradí.
ISR funkcie nevracajú žiadnu hodnotu a nemajú žiadny parameter. Ak je teda potrebné vo vnútri ISR funkcie zmeniť stav správania aplikácie, je na to možné použiť globálne premenné. Je to vlastne jediný spôsob, pomocou ktorého je možné prenášať údaje medzi ISR a hlavným programom.
(slide) Pri tvorbe ISR je dobré dodržiavať niekoľko odporúčaní:
- ISR majú byť čo najkratšie a čo najrýchlejšie, aby zbytočne nebrzdili hlavný program alebo prípadne ďalšie prerušenia, ktoré môžu nastať.
- Je potrebné sa vo vnútri ISR vyhnúť použitiu funkcie
delay()
! - Nepoužívať sériovú komunikáciu!
- Ak programujete v jazyku C, tak globálne premenné, ktoré
používate na zdieľanie údajov medzi ISR a programom, označte
pomocou kvalifikátora
volatile
! Tým poviete prekladaču, že táto premenná môže byť použiteľná kdekoľvek v kóde a prekladač jej obsah vždy pri použití znovu načíta a nebude sa spoliehať na jej kópiu v registri. Zabránite tak aj prípadným optimalizáciám prekladača, vďaka ktorým by ju mohol napr. vyhodiť, pretože sa nepoužíva (v hlavnom programe). - Nevypínať ani nezapínať podporu prerušení vo vnútri ISR. V tomto prípade však existujú výnimky, ktoré budú opísané neskôr v kapitole.
Reasons to use Interrupts
(slide) Existuje veľa dôvodov, prečo prerušenia používať . Niektoré z nich sú tieto:
- To detect pin changes (eg. rotary encoders, button presses)
- Watchdog timer (eg. if nothing happens after 8 seconds, interrupt me)
- Timer interrupts - used for comparing/overflowing timers
- SPI data transfers
- I2C data transfers
- USART data transfers
- ADC conversions (analog to digital)
- EEPROM ready for use
- Flash memory ready
Types of Interrupts
(slide) Pri práci s mikrokontrolérmi je možné prerušenia rozdeliť do dvoch skupín:
- hardvérové prerušenia, známe tiež ako externé prerušenia, alebo tiež pin-change prerušenia, a
- softvérové prerušenia, ktoré sú známe ako interné prerušenia alebo tiež časovače.
Ako už názov napovedá, signál prerušenia prichádza v prípade hardvérových alebo externých prerušení z externého zariadenia. Toto zariadenie je s mikrokontrolérom priamo prepojené. Keďže sú prerušenia asynchrónne, k prerušeniu môže dôjsť kedykoľvek.
Interné prerušenia zasa referujú na čokoľvek vo vnútri mikrokontroléra, čo dokáže vyvolať prerušenie. Príkladom môžu byť napríklad časovače, pomocou ktorých je možné zabezpečiť, aby k vyvolaniu prerušenia dochádzalo pravidelne napr. každú 1 sekundu.
Interrupt Vectors in ATmega328P
V jednej chvíli môžu byť naraz vyvolané viaceré žiadosti o prerušenie a mikrokontrolér sa musí rozhodnúť, ktorá z nich bude ošetrená ako prvá. Je teda potrebné, aby mikrokontrolér vedel povedať, ktoré prerušenia majú prednosť pred inými.
Mikrokontrolér obsahuje tzv. tabuľku vektorov prerušení (viď. tabuľka XXX). Táto tabuľka sa nachádza na začiatku programovej flash pamäti a obsahuje adresy ISR funkcií jednotlivých prerušení. V ich poradí je však aj priorita - čím má prerušenie nižšiu adresu, resp. vektor prerušenia má nižšie číslo, tým má vyššiu prioritu. Z tabuľky je teda možné vidieť, že najvyššiu prioritu má prerušenie od zdroja
RESET
a najnižšiu prioritu od zdrojaSPM READY
.
Vector No. | Program Address | Source | Interrupt Definition |
---|---|---|---|
1 | 0x0000 |
RESET |
External Pin, Power-on Reset, Brown-out Reset and Watchdog System Reset |
2 | 0x0002 |
INT0 |
External Interrupt Request 0 |
3 | 0x0004 |
INT1 |
External Interrupt Request 1 |
4 | 0x0006 |
PCINT0 |
Pin Change Interrupt Request 0 |
5 | 0x0008 |
PCINT1 |
Pin Change Interrupt Request 1 |
6 | 0x000A |
PCINT2 |
Pin Change Interrupt Request 2 |
7 | 0x000C |
WDT |
Watchdog Time-out Interrupt |
8 | 0x000E |
TIMER2 COMPA |
Timer/Counter2 Compare Match A |
9 | 0x0010 |
TIMER2 COMPB |
Timer/Counter2 Compare Match B |
10 | 0x0012 |
TIMER2 OVF |
Timer/Counter2 Overflow |
11 | 0x0014 |
TIMER1 CAPT |
Timer/Counter1 Capture Event |
12 | 0x0016 |
TIMER1 COMPA |
Timer/Counter1 Compare Match A |
13 | 0x0018 |
TIMER1 COMPB |
Timer/Coutner1 Compare Match B |
14 | 0x001A |
TIMER1 OVF |
Timer/Counter1 Overflow |
15 | 0x001C |
TIMER0 COMPA |
Timer/Counter0 Compare Match A |
16 | 0x001E |
TIMER0 COMPB |
Timer/Counter0 Compare Match B |
17 | 0x0020 |
TIMER0 OVF |
Timer/Counter0 Overflow |
18 | 0x0022 |
SPI , STC |
SPI Serial Transfer Complete |
19 | 0x0024 |
USART , RX |
USART Rx Complete |
20 | 0x0026 |
USART , UDRE |
USART, Data Register Empty |
21 | 0x0028 |
USART , TX |
USART, Tx Complete |
22 | 0x002A |
ADC |
ADC Conversion Complete |
23 | 0x002C |
EE READY |
EEPROM Ready |
24 | 0x002E |
ANALOG COMP |
Analog Comparator |
25 | 0x0030 |
TWI |
2-wire Serial Interface |
26 | 0x0032 |
SPM READY |
Store Program Memory Ready |
: Reset and Interrupt Vectors in ATmega328 and ATmega328P
Handling the External Interrupts with Arduino
Vrátime sa teda k predchádzajúcemu zdrojovému kódu, kedy sme na detekciu pohybu využili metódu polling-u. Tentokrát sa problém pokúsime vyriešiť pomocou prerušenia. Konkrétne sa bude jednať o externé prerušenie, keďže prerušenie vyvolá PIR senzor tým, že pošle signál do mikrokontroléra vtedy, keď bude detekovať pohyb.
(slide) Ošetrenie prerušenia sa inicializuje pomocou funkcie
attachInterrupt()
. Inicializácia môže prebehnúť kdekoľvek v programe, ale pokiaľ sa ošetrenie prerušenia v programe nemení, je ideálne ho inicializovať vo funkciisetup()
. Táto funkcia má tri parametre, ktoré hovoria o tom, čo všetko je potrebné vedieť pri ošetrovaní prerušenia:- číslo prerušenia, ktoré je potrebné ošetriť,
- názov (resp. adresu) ISR funkcie, ktorá sa zavolá na jeho ošetrenie, a
- režim prerušenia, ktorý definuje, aké správanie na pin-e vyvolá prerušenie.
Poznámka
Miesto čísla prerušenia, ktoré má byť ošetrené, je vhodnejšie použiť číslo pin-u, na ktorom je toto prerušenie sledované. To je možné dosiahnuť pomocou funkcie
digitalPinToInterrupt(pin)
, ktorá automaticky prevedie číslo pin-u na číslo prerušenia. Týmto spôsobom je tiež možné zabezpečiť prenositeľnosť medzi viacerými platformami.(slide) Pozrime sa najprv na to, aké správanie na pin-e vyvolá prerušenie. Prototypovacia doska Arduino UNO pozná tieto štyri režimy prerušenia:
LOW
- Prerušenie je vyvolané vtedy, keď sa na pine nachádza úroveňLOW
. Tento proces sa deje napríklad vtedy, ak je tlačidlo pripojené k digitálnemu pinu v režimeINPUT_PULLUP
a po jeho stlačení sa na pin privedie úroveňLOW
.CHANGE
- Prerušenie je vyvolané vtedy, keď dôjde k zmene úrovne pinu buď zHIGH
naLOW
alebo zLOW
naHIGH
. Tento proces sa deje napríklad pri stláčaní prepínača.RISING
- Prerušenie je vyvolané vtedy, keď dôjde k zmene úrovne zLOW
naHIGH
. Tento proces sa deje napríklad pri stlačení tlačidla.HIGH +---------- | | ^ LOW | ------->-+
FALLING
- Prerušenie je vyvolané vtedy, keď dôjde k zmene úrovne zHIGH
naLOW
. Tento proces sa deje napríklad pri uvoľnení stlačeného tlačidla.HIGH -------->-+ | V | | LOW +---------
Poznámka
Prototypovacie dosky Arduino Due, Zero a MKR1000 majú navyše režim
HIGH
. K tomuto prerušeniu dôjde vždy vtedy, keď sa na pine bude nachádzať úroveňHIGH
.
(slide) Na základe uvedených režimov prerušenia mikrokontroléra sa je možné stretnúť ešte s nasledujúcim rozdelením externých prerušení:
Level Interrupts - Prerušenie je vyvolané zakaždým, keď sa na vstupe objaví signál konkrétnej úrovne (
HIGH
aleboLOW
). Pri tomto type prerušenia je dobré dať pozor na to, že pri nezmenenom signále môže k prerušeniu dochádzať opakovane aj počas ošetrovania predchádzajúceho prerušenia.Edge Interrupts - Prerušenie je vyvolané vtedy, keď dôjde k zmene jednej úrovne signálu na druhú (napr. ak dôjde k zmene úrovne z
HIGH
naLOW
alebo zLOW
naHIGH
).
(slide) Každý mikrokontrolér je špecifický tým, že na zachytenie externého prerušenia z pripojeného zariadenia nie je možné použiť každý digitálny pin. Vždy je preto potrebné overiť si možnosti mikrokontroléra v jeho dokumentácii. V prípade mikrokontrolérov Arduino sa je možné orientovať pomocou tabuľky XXX.
Board | Digital Pins Usable For Interrupts |
---|---|
Uno, Nano, Mini, other 328-based | 2, 3 |
Uno WiFi Rev.2 | all digital pins |
Mega, Mega2560, MegaADK | 2, 3, 18, 19, 20, 21 |
Micro, Leonardo, other 32u4-based | 0, 1, 2, 3, 7 |
Zero | all digital pins, except 4 |
MKR Family boards | 0, 1, 4, 5, 6, 7, 8, 9, A1, A2 |
Due | all digital pins |
101 | all digital pins (Only pins 2, 5, 7,
8, 10, 11, 12, 13 work with
CHANGE ) |
V porovnaní s mikrokontrolérom ESP8266 je na tom ATmega 328P horšie, pretože je možné použiť piny
GPIO0
ažGPIO15
. To umožňuje naraz sledovať až 16 rozličných prerušení.PIR senzor je aktuálne v IoT zariadení na detekciu pohybu pripojený k pin-u č. 2. Ten podľa uvedenej tabuľky je možné použiť na zachytávanie externých prerušení.
Následne je potrebné už len poznať názvy ISR funkcií. V predchádzajúcom prípade sme používali funkcie dve a to
alarm()
aidle()
. Funkciaalarm()
bola zavolaná vtedy, keď došlo k zisteniu pohybu (na výstupnom pine PIR senzoru došlo k prechodu z úrovneLOW
do úrovneHIGH
). Funkciaidle()
bola zasa vyvolaná vtedy, keď tento pohyb pominul (na výstupnom pine PIR senzoru došlo k prechodu z úrovneHIGH
na úroveňLOW
).Vzhľadom na uvedené správanie vieme presne určiť, v akom režime prerušenia má byť zavolaná funkcia
alarm()
a v akom funkciaidle()
:alarm()
sa bude volať v režimeRISING
idle()
sa bude volať v režimeFALLING
V kóde funkcie
setup()
to teda bude vyzerať nasledovne:(digitalPinToInterrupt(PIN_PIR), attachInterrupt, RISING); alarm(digitalPinToInterrupt(PIN_PIR), attachInterrupt, FALLING); idle
Tu však pozor! Každý mikrokontrolér obsahuje tabuľku vektorov prerušení (viď tabuľka XXX). Každý riadok v tejto tabuľke obsahuje informáciu o tom, ktorá ISR funkcia sa použije na ošetrenie ktorého zdroja prerušenia. To znamená, že na ošetrenie prerušenia na jednom vstupe sa použije len jedna ISR funkcia. V zázname sa nenachádza informácia o tom, v akom režime môže k prerušeniu dôjsť. Ak sme teda v našom prípade na jeden pin namapovali pomocou funkcie
attachInterrupt()
dve ISR funkcie, tak sme vlastne prepísali ošetrenie prerušenia prvou funkciou pomocou druhej funkcie. Kód sa úspešne preloží, aj sa spustí, ale k ošetreniu prerušenia dôjde len pomocou ISR funkcieidle()
v režimeFALLING
.Aj napriek tomu je však možné prekonfigurovať ošetrenie prerušenia neskôr v programe. Akonáhle teda k prerušeniu dôjde a vyvolá sa ISR funkcia, jej súčasťou bude volanie funkcie
attachInterrupt()
na nastavenie nového ošetrenia prerušenia za iných podmienok. Týmto spôsobom si budú jednotlivé ISR funkcie prehadzovať ošetrenie prerušenia navzájom.Aby všetko pracovalo správne, je potrebné aplikovať tieto informácie a refaktorovať funkciu
setup()
z predchádzajúceho riešenia. Globálnu premennúisMovement
je potrebné označiť kľúčovým slovomvolatile
a zadefinovať ošetrenie prerušenia pomocou ISR funkciealarm()
v režimeRISING
(zistenie pohybu). Aktualizovaný kód funkciesetup()
sa nachádza vo výpise XXX.#include <Arduino.h> #define PIN_LED 8 #define PIN_PIR 2 volatile bool isMovement; void idle(); void alarm(); void setup(){ // setup serial .begin(9600); Serialwhile(!Serial); // set pin modes (PIN_LED, OUTPUT); pinMode(PIN_PIR, INPUT); pinMode // initial state = false; isMovement // enter idle state (); idle}
Následne je potrebné upraviť ISR funkcie
alarm()
aidle()
. Okrem pôvodného správania v každej z nich predefinujeme ošetrenie prerušenia:v prípade ISR funkcie
alarm()
predefinujeme ošetrenie prerušenia pomocou funkcieidle()
v režimeFALLING
(zo stavuALARM
zariadenie prejde do stavuIDLE
, ak na pine dôjde k prechodu z úrovneHIGH
na úroveňLOW
)v prípade ISR funkcie
idle()
predefinujeme ošetrenie prerušenia pomocou funkciealarm()
v režimeRISIGN
(zo stavuIDLE
zariadenie prejde do stavuALARM
, ak na pine dôjde k prechodu z úrovneLOW
na úroveňHIGH
)
Po úprave budú tieto funkcie vyzerať takto:
void idle(){ .println("> Idle State"); Serial // update state = false; isMovement (PIN_LED, LOW); digitalWrite // (re)attach interrupt (digitalPinToInterrupt(PIN_PIR), attachInterrupt, RISING); alarm} void alarm(){ .println("> Alarm State"); Serial // update state = true; isMovement (PIN_LED, HIGH); digitalWrite // (re)attach interrupt (digitalPinToInterrupt(PIN_PIR), attachInterrupt, FALLING); idle}
Nakoniec už zostáva len funkcia
loop()
, ktorá bude v tomto prípade prázdna. Celý kód, ktorý bol použitý v prípade riešenia pomocou metódy pooling bol totiž presunutý do ISR funkcií. Týmto sme využili všetky výhody, ktoré ponúka mechanizmus prerušení a odstránili sme všetky nedostatky, ktoré ponúka polling. Vo funkciiloop()
teda zostáva priestor na vlastný ḱód, ktorý môže na základe globálnej premennejisMovement
vykonávať ďalšie operácie.void loop(){ // nothing to do :-/ }
Kompletný výpis kódu sa nachádza vo výpise XXX.
#include <Arduino.h> #define PIN_LED 8 #define PIN_PIR 2 bool isMovement; void idle(); void alarm(); void idle(){ .println("> Idle State"); Serial // update state = false; isMovement (PIN_LED, LOW); digitalWrite // (re)attach interrupt (digitalPinToInterrupt(PIN_PIR), attachInterrupt, RISING); alarm} void alarm(){ .println("> Alarm State"); Serial // update state = true; isMovement (PIN_LED, HIGH); digitalWrite // (re)attach interrupt (digitalPinToInterrupt(PIN_PIR), attachInterrupt, FALLING); idle} void setup(){ // setup serial .begin(9600); Serialwhile(!Serial); // set pin modes (PIN_LED, OUTPUT); pinMode(PIN_PIR, INPUT); pinMode // initial state = false; isMovement // enter idle state (); idle} void loop(){ // nothing to do :-( }
Poznámka
Sériová komunikácia vo vnútri ISR.
Toto riešenie je možné ešte zjednodušiť a vrátiť sa tak k pôvodnému konceptu, kedy boli prerušenia
RISING
aFALLING
zadefinované naraz. Upravíme zapojenie tak, že výstup z PIR senzoru pripojíme naraz ku pinu 2 aj 3. na pine 2 bude mikrokontrolér sledovať prerušenie typuRISING
a na pine 3 prerušenie typuFALLING
.Upravená schéma zapojenia sa nachádza na obrázku XXX a aktualizovaná podoba kódu riešenia sa nachádza vo výpise XXX.
#include <Arduino.h> #define PIN_LED 8 #define PIN_IDLE 2 #define PIN_ALARM 3 bool isMovement; void alarm(); void idle(){ .println("> Idle State"); Serial // update state = false; isMovement (PIN_LED, LOW); digitalWrite} void alarm(){ .println("> Alarm State"); Serial // update state = true; isMovement (PIN_LED, HIGH); digitalWrite} void setup(){ // setup serial .begin(9600); Serialwhile(!Serial); // set pin modes (PIN_LED, OUTPUT); pinMode(PIN_ALARM, INPUT); pinMode(PIN_IDLE, INPUT); pinMode // initial state = false; isMovement // attach interrupt (digitalPinToInterrupt(PIN_ALARM), attachInterrupt, RISING); alarm(digitalPinToInterrupt(PIN_IDLE), attachInterrupt, FALLING); idle} void loop(){ // nothing to do :-( }
Týmto prístupom sa síce sprehľadnil a zjednodušil kód, ale stratila sa možnosť využiť druhý pin pre možnosť sledovania prerušení z ďalšieho zariadenia. Preto je vždy dobré takýto prístup zvážiť.
Turning Interrupts On and Off
Ošetrovanie prerušení je po zapnutí mikrokontrolérov ATmega 328P zapnuté. Automaticky sa však vypnú v okamihu, keď dôjde k ošetreniu prerušenia a pomocou ISR funkcie a opät sa automaticky zapnú, keď sa ISR funkcia ukončí.
Existujú však dve makrá, pomocou ktorých je možné ošetrovanie prerušení globálne vypínať a zapínať aj počas vykonávania ISR funkcie. Tieto makrá sú:
interrupts()
- globálne povolí ošetrovanie prerušenínoInterrupts()
- globálne zakáže ošetrovanie prerušení
Nasledujúci fragment kódu ilustruje situáciu, ak by sme chceli opätovne zapnúť prerušenia v ISR funkcii
alarm()
:void alarm(){ (); interrupts= true; isMovement (PIN_LED, HIGH); digitalWrite(digitalPinToInterrupt(PIN_PIR), attachInterrupt, FALLING); idle}
Upozornenie
Tu je však potrebné si dať veľký pozor, pretože ich nesprávnym použitím môžete dosiahnuť nepredvídateľné správanie. Napríklad povolením prerušení v ISR funkcii môžete dosiahnuť rekurzívne vykonávanie ISR funkcie pri ošetrovaní Level prerušení, ak sa úroveň signálu nezmení.
Poznámka
Na globálne vypínanie a zapínanie prerušení je možné použiť priamo aj AVR funkcie
sei()
acli()
. Funkciasei()
globálne prerušenia zapína a funkciacli()
globálne prerušenia vypína. Pri bližšom pohľade do knižniceArduino.h
je možné zistiť, že makráinterrupts()
anoInterrupts()
volajú práve tieto AVR funkcie:#define interrupts() sei() #define noInterrupts() cli()
V texte však budú použité len makrá
interrupts()
anoInterrupts()
kvôli čítateľnejšiemu kódu.
Handling the Internal Interrupts with Arduino
Do kategórie interných prerušení patria časovače. Pomocou nich je možné napríklad presne načasovať spúšťanie časti programu, čo sa častokrát používa aj na vytvorenie dojmu “paralelizácie” vykonávaných úloh.
Mikrokontrolér ATmega328P obsahuje 3 časovače označené ako
TIMER0
,TIMER1
aTIMER2
.TIMER0
aTIMER2
sú 8 bitové, zatiaľ čoTIMER2
je 16 bitový časovač. Ich funkcionalita však závisií od frekvencie mikrokontroléra. V prípade Arduina je použitý externý oscilátor s frekvenciou 16 MHz.Kažý časovač môže generovať jeden alebo viac prerušení. Tieto sú:
Compare Match Interrupt - Tento typ prerušenia vznikne v situácii, keď je potrebné, aby sa časovač zastavil pri dosiahnutí konkrétnej hodnoty. Jeho aktuálna hodnota sa porovnáva s požadovanou a keď dôjde k zhode, dôjde k vyvolaniu tohto prerušenia.
Overflow Interrupt - Každý časovač používa vnútorné počítadlo, ktoré má svoj rozsah v závislosti od veľkosti použitého registra. Hodnota počítadla sa postupne zvyšuje, a keď je dosiahnutá maximálna hodnota a tá sa znova zvýši o jednotku, dôjde k pretečeniu a vyvolaniu tohto typu prerušenia.
Input Capture Interrupt - Tento typ prerušenia sa používa na zachytenie vzniknutej udalosti na pine. K prerušeniu dôjde vtedy, keď je na pine zaznamenaná konkrétna hrana signálu. Tá môže byť vzostupná, zostupná alebo akákoľvek. Časovač dokáže zaznamenať čas vzniku tejto udalosti.
S použitím týchto časovačov sa je možné stretnúť pri programovaní Arduina bežne. Časovač
TIMER0
sa používa pre funkcie pracujúce s časom, ako súdelay()
,millis()
amicros()
.TIMER1
je zasa možné nájsť v knižniciServo.h
aTIMER2
sa používa pri generovaní zvuku pomocou funkcietone()
. FunkciaanalogWrite()
využíva každý časovač, ale každý pre rozličné piny.Prehľad vlastností dostupných časovačov na mikrokontroléri ATmega328P sa nachádza v tabuľke XXX.
Timer | Size | Range | Possible Interrupts |
---|---|---|---|
TIMER0 |
8 bits | 0-255 | Compare Match, Overflow |
TIMER1 |
16 bits | 0-65535 | Compare Match, Overflow, Input Capture |
TIMER2 |
8 bits | 0-255 | Compare Match, Overflow |
- Osobitným časovačom je Watchdog. Ak sa zariadenie dostane
do chybového stavu, je jeho úlohou po uplynutí časového intervalu
mikrokontrolér reštartovať. Pre prácu s Watchdog časovačom je k
dispozícii knižnica
avr/wdt.h
.
TimerOne Library
S časovačmi je možné pracovať dvoma spôsobmi: pomocou štandardných AVR knižníc alebo pomocou knižníc tretích strán. A práve knižnica TimerOne ponúka veľmi jednoduché API, ktoré zakryje nízkoúrovňový prístup ponúkaný knižnicami AVR.
Táto knižnica poskytuje kolekciu funkcií na nastavenie 16 bitového časovača označovaného ako
TIMER1
(odtiaľ názov knižnice). Pôvodným zámerom bolo vytvoriť jednoduchý a rýchly spôsob na nastavenie periódy PWM. Nakoniec však bol do knižnice zahrnutý aj prerušenie timer overflow a iné vlastnosti.Na prácu s knižnicou stačí poznať len tieto funkcie:
Timer1.initialize(microseconds)
- Táto funkcia inicializuje prácu s časovačom a musí byť zavolaná ako prvá. Parametermicroseconds
definuje periódu časovača.Timer1.attachInterrupt(function)
- Vždy po uplynutí periódy sa spustí ISR funkcia, ktorej názvoj je uvedený v parametri.Timer1.detachInterrupt()
- Zakáže prerušenie, takže ISR funkcia sa prestane spúšťať.
Pomocou knižnice je však možné ovládať aj už spustený časovač pomocou týchto funkcií:
Timer1.start()
- Spustí časovač a začne novú periódu.Timer1.stop()
- Zastaví časovač.Timer1.restart()
- Reštartuje časovač od začiatku novej periódy.
Timers in Motion Detection Scenario
Pre ilustráciu použitia časovačov upravíme scenár vytváraného zariadenia na detekciu pohybu. K existujúcim stavom bude pridaný nový stav s názvom
WATCHING
. Do neho systém prejde zo stavuIDLE
po zistení pohybu. V staveWATCHING
sa zasvieti LED dióda a spustí sa časovač. Pokiaľ sa v priebehu najbližších 10 sekúnd pohyb neukončí, systém prejde do stavuALARM
a LED dióda sa rozbliká. Ak sa ale v priebehu týchto 10 sekúnd pohyb stratí, dióda zhasne a systém prejde späť do stavuIDLE
. Zo stavuALARM
je možné prejsť do stavuIDLE
stlačením tlačidla. Aktualizovaný stavový diagram sa nachádza na obrázku XXX.Keďže do systému pribudlo tlačidlo, dôjde aj k atualizácii schémy zapojenia. Tá sa nachádza na obrázku XXX.
Zmien sa dočkal aj samotný kód. Vo funkci
setup()
prebehne štandardná inicializácia, ale rovnako sa v nej inicializuje časovač a nastaví sa jeho perióda na 1 sekundu. Z funkcie sa systém dostane rovno do stavuIDLE
.Novou je funkcia
watch()
. Tá v premennejcountdown
nastaví 10 sekundový odpočet a nastaví ISR funkciutick()
pre ošetrenie prerušenia časovača. Tá sa bude volať každú sekundu a zakaždým z premennejcountdown
odpočíta 1. Pri dosiahnutí hodnoty 0 systém prejde do stavuALARM
.Kompletný výpis kódu sa nachádza vo výpise XXX.
#include <Arduino.h> #include <TimerOne.h> #define PIN_LED 8 #define PIN_PIR 2 #define PIN_BTN 3 volatile bool isMovement; volatile byte countdown; void idle(); void watch(); void alarm(); void idle(){ .println("> Idle State"); Serial = false; isMovement (PIN_LED, LOW); digitalWrite // reattach interrupts (digitalPinToInterrupt(PIN_BTN)); detachInterrupt(digitalPinToInterrupt(PIN_PIR), attachInterrupt, RISING); watch.detachInterrupt(); Timer1} void tick(){ --; countdownif(countdown == 0){ (); alarm} } void watch(){ .println("> Watch State"); Serial // update state (PIN_LED, HIGH); digitalWrite // reattach interrupts (digitalPinToInterrupt(PIN_PIR), attachInterrupt, FALLING); idle= 10; countdown .attachInterrupt(tick); Timer1.restart(); Timer1} void alarm(){ .println("> Alarm State"); Serial // update state (PIN_LED, HIGH); digitalWrite= true; isMovement // reattach interrupts .detachInterrupt(); Timer1(digitalPinToInterrupt(PIN_PIR)); detachInterrupt(digitalPinToInterrupt(PIN_BTN), attachInterrupt, LOW); idle} void setup(){ // set pin modes (PIN_LED, OUTPUT); pinMode(LED_BUILTIN, OUTPUT); pinMode(PIN_PIR, INPUT); pinMode(PIN_BTN, INPUT_PULLUP); pinMode .begin(9600); Serialwhile(!Serial); // setup timer .initialize(1 * 1000000); Timer1 // enter idle state (); idle} void loop(){ if (isMovement == true){ (PIN_LED, HIGH); digitalWrite(1000); delay(PIN_LED, LOW); digitalWrite(1000); delay} }
Pros and Cons of Interrupts
Výhody:
- lepší reakčný čas v porovnaní s polling-om
- šetrenie zdrojov
Nevýhody:
- Prerušenia sa výrazne horšie ladia, pretože k prerušeniu môže dôjsť aj počas ladenia programu. A vy zrazu neviete, koľko prerušení bolo vykonaných medzi krokovaním aktuálnej časti programu.
Measuring Power when Using Interrupts
- žiadna zmena
Putting Your Device to Sleep
To, čo sa aktuálne podarilo použitím prerušení, je odstrániť kód z hlavnej slučky programu. Mohlo by sa zdať, že tým, že je táto slučka prázdna, je možné ušetriť energiu. Toto zdanie je však mylné. Mikrokontrolér je totiž stále aktívny a stále v ňom dochádza k volaniu funkcie
loop()
, aj keď je jej telo prázdne. Môžete si vyskúšať, čo dosiahnete na svojom počítači, ak v interpretéri príkazového riadku napíšete takýto skript:while true; do # nothing to do in here : done
Ak sa následne pozriete na vyťaženie procesora uvidíte, že je (v prípade viacproserového systému je jedno jadro) vyťažené na 100%. A to aj napriek tomu, že uvedený fragment kódu nič nerobí.
Ako teda usporiť energiu v prípade, ak je obsah funkcie
loop()
prázdny a mikrokontrolér “nič” nevykonáva? Odpoveďou je uspanie mikrokontroléra.
What is Sleep Mode?
Režim spánku je špeciálny režim mikrokontroléra, do ktorého je možné mikrokontrolér prepnúť v čase jeho neaktivity. V tomto režime sa mikrokontrolér prepne do režimu nízkej spotreby, čím je možné elektrickú energiu ušetriť. Jej ušetrené množstvo závisí od toho, aké všetky komponenty zostanú napájané aj po prechode do režimu spánku. Stav mikrokontroléra sa v režime spánku nestratí, pretože zostáva v jeho pamäti.
Princíp fungovania je podobný, ako keď váš domáci spotrebič, ako je napr. televízor, DVD prehrávač alebo set-top box, vypnete pomocou diaľkového ovládača. Zariadenie sa nevypne úplne, pretože čaká na signál z diaľkového ovladača, ktorý ho opätovne zobudí (zapne) a uvedie do plnej prevádzky. Počas režimu spánku je však jeho odber elektrickej energie minimálny v porovnaní s množstvom elektrickej energie, ktorú odoberá pri plnej prevádzke. Mnohé zariadenia tento režim reprezentujú pomocou červenej LED diódy.
Režim spánku nefunguje bez použitia prerušení. Ak sa raz mikrokontrolér uspí, okrem prerušenia ho vie zobudiť len reset (ktorý je vlastne tiež prerušením). Prerušenie v tomto prípade funguje ako budík - zobudí mikrokontrolér, ktorý prerušenie automaticky obslúži pomocou príslušnej IRS funkcie. Následne môže mikrokontrolér opäť uspať alebo sa začne vykonávať hlavný program.
Putting Arduino to Sleep
(slide) Množstvo ušetrenej energie bude závisiť od toho, akú prototypovaciu dosku Arduino použijete. Rozličné verzie Arduín obsahujú rozličné súčasti, ktoré tiež spotrebujú nejakú energiu. Ak napríklad použijete Arduino Uno, v režime spánku bude mať spotrebu 19 mA, zatiaľ čo v bežnej prevádzke bude mať spotrebu v rozmedzí 30 až 40 mA. Ak ale použijete Arduino Pro Mini, jeho spotreba počas spánku bude len 0.57 mA a v bežnej prevádzke 25 mA. Rozdiel je teda značný.
- TODO: blokova schema arduina so sucastami, ktore je mozne vypnut
To, aké režimy spánku podporuje konkrétny mikrokontrolér, je potrebné vždy overiť v jeho dokumentácii. V prípade mikrokontroléra ATmega328P, ktorý je srdcom Arduino Uno sa jedná o 6 režimov, z ktorých je len 5 dostupných v hlavičkovom súbore
avr/sleep.h
:- Idle (
SLEEP_MODE_IDLE
) - ADC Noise Reduction (
SLEEP_MODE_ADC
) - Power-save (
SLEEP_MODE_PWR_SAVE
) - Standby (
SLEEP_MODE_STANDBY
) - Power-down (
SLEEP_MODE_PWR_DOWN
)
- Idle (
Najmenej úsporným režimom je režim Idle. Je to taktiež predvolený režim, takže ak počas behu programu nebude explicitne zvolený iný režim, pri uvedení mikrokontroléra do režimu spánku sa použije režim Idle. Z tohto režimu je možné mikrokontrolér zobudiť takmer ľubovoľným spôsobom.
Najviac úsporným režimom je režim Power-down. V tomto režime je zakázaných najviac súčastí mikrokontroléra a zo spánku ho je možné prebudiť len pomocou externých prerušení.
Jednotlivé režimy sa od seba navzájom líšia tým, aké všetky súčasti mikrokontroléra budú vypnuté, ako aj tým, akým spôsobom bude zasa mikrokontrolér prebudený. V tabuľke XXX sa nachádza prehľad možností, ktorými je možné mikrokontrolér ATmega328P zobudiť. Pre konkrétny mikrokontrolér je vždy dobré overiť jeho možnosti v dokumentácii.
Wake-up Sources | Idle | ADC Noise Reduction | Power-save | Standby | Power-down |
---|---|---|---|---|---|
INT1, INT0 and Pin Change | X | X | X | X | X |
TWI Address Match | X | X | X | X | X |
Timer2 | X | X | X | ||
SPM/EEPROM Ready | X | X | |||
A/D Converter | X | X | |||
Watchdog Timer | X | X | X | X | X |
Other I/O | X |
Netreba zabudnúť na to, že mikrokontrolér sa dá z každej úrovne spánku vždy úspešne prebudiť pomocou RESET-u.
Pre prácu s režimom spánku je potrebné do programu načítať hlavičkový súbor
avr/sleep.h
. Ten obsahuje všetky potrebné makrá a funkcie na prácu s režimom spánku. Vo všeobecnosti bude stačiť použiť tieto z nich:set_sleep_mode()
- funkcia na nastavenie režimu spánku, pričom parametrom môže byť lenSLEEP_MODE_IDLE
,SLEEP_MODE_ADC
,SLEEP_MODE_PWR_SAVE
,SLEEP_MODE_STANDBY
aleboSLEEP_MODE_PWR_DOWN
sleep_mode()
- makro na prechod do režimu spánku spolu s nastavením bituSE
(Sleep Enable) pred prechodom do spnánku a aj jeho vyčistením po zobudeníPoznámka
V rozličných zdrojoch sa dá stretnúť s postupnosťou volaní týchto makier:
(); sleep_enable(); sleep_cpu(); sleep_disable
Volaním makra
sleep_mode()
je možné nahradiť tieto tri makrá naraz. Makrosleep_mode()
totiž najprv bitSE
nastaví (volaniesleep_enable()
), následne mikrokontrolér uspí (volaniesleep_cpu()
) a po zobudení zasa bitSE
vyčistí (volaniesleep_disable()
).
Jednoduchá ilustrácia uvedenia mikrokontroléra do režimu spánku sa nachádza v nasledujúcom fragmente kódu, ktorý predstavuje modifikáciu štandardného príkladu Blink. Na 500 ms sa rozsvieti vstavaná LED dióda, na čo sa mikrokontrolér uvedie do najtvrdšieho spánku (Power-down). Nakoľko však pred spánkom nebol zadefinovaný žiadny spôsob opätovného prebudenia, mikrokontrolér sa už nezobudí a LED dióda už nezhasne. To znamená, že úroveň
HIGH
zostane na pin-e nezmenená aj po uspatí. Jediný spôsob, ako ho opätovne prebudiť, je stlačiť tlačidloRESET
.#include <Arduino.h> #include <avr/sleep.h> void setup(){ (LED_BUILTIN, OUTPUT); pinMode(SLEEP_MODE_PWR_DOWN); set_sleep_mode} void loop(){ // blink (LED_BUILTIN, HIGH); digitalWrite(500); delay // sleep (); sleep_mode // unreachable code (LED_BUILTIN, LOW); digitalWrite(500); delay}
Upozornenie
Tu však pozor! Ak sa mikrokontrolér uspí v režime Power-down bez toho, aby ste definovali spôsob jeho zobudenia pomocou prerušenia, mikrokontrolér sa už nezobudí. Jediným spôsobom, ako ho zobudiť je privedením signálu na pin
RESET
. Dôsledkom tejto situácie je, že ak sa pokúsite mikrokontrolér preprogramovať v stave spánku, nebudete úspešní. Nástroj pre nahratie kódu do mikrokontroléra sa bude v prípade neúspechu pokúšať nahrať kód opakovane. Stačí v tomto momente mikrokontrolér resetnúť. Tým sa mikrokontrolér zobudí a počas jeho štartovania sa kód do mikrokontroléra nahrá.
Waking the Microcontroller with External Interrupts
(slide) Upravíme prípad použitia zariadenia na rozpoznávanie pohybu. Tentokrát sa zariadenie po spustení uspí. Akonáhle PIR senzor detekuje pohyb, zariadenie sa zobudí a začne blikať externou diódou. Blikať bude dovtedy, kým sa nestlačí tlačidlo, ktoré zariadenie zresetuje, vypne LED diódu a zariadenie uspí.
Stavový diagram zariadenia sa veľmi nebude líšiť od predchádzajúceho. Zariadenie sa bude môcť opät nachádzať v jednom z dvoch stavov. Zmenia sa však prechody medzi stavmi.
Aktualizovaná schéma zapojenia sa nachádza na obrázku XXX.
Zdrojový kód riešenia sa nachádza vo výpise XXX. Za najväčšiu odlišnosť oproti predchádzajúcemu kódu je možné považovať prechod do režimu spánku.
#include <Arduino.h> #include <TimerOne.h> #include <avr/sleep.h> #define PIN_LED 8 #define PIN_PIR 2 #define PIN_BTN 3 volatile bool isMovement; volatile byte countdown; void idle(); void watch(); void alarm(); void idle(){ = false; isMovement (PIN_LED, LOW); digitalWrite(LED_BUILTIN, LOW); digitalWrite // reattach interrupts (digitalPinToInterrupt(PIN_BTN)); detachInterrupt(digitalPinToInterrupt(PIN_PIR), attachInterrupt, RISING); watch.detachInterrupt(); Timer1 // go to sleep (SLEEP_MODE_PWR_DOWN); set_sleep_mode(); interrupts(); sleep_mode} void tick(){ --; countdown if(countdown == 0){ (); alarm} // go to sleep (); interrupts(); sleep_mode} void watch(){ // update state (PIN_LED, HIGH); digitalWrite // reattach interrupts (SLEEP_MODE_ADC); set_sleep_mode(digitalPinToInterrupt(PIN_PIR), attachInterrupt, FALLING); idle= 10; countdown .attachInterrupt(tick); Timer1.restart(); Timer1 // go to sleep (); interrupts(); sleep_mode} void alarm(){ // update state (PIN_LED, HIGH); digitalWrite= true; isMovement // reattach interrupts .detachInterrupt(); Timer1(digitalPinToInterrupt(PIN_PIR)); detachInterrupt(digitalPinToInterrupt(PIN_BTN), attachInterrupt, LOW); idle} void setup(){ // set pin modes (PIN_LED, OUTPUT); pinMode(PIN_PIR, INPUT); pinMode(PIN_BTN, INPUT_PULLUP); pinMode // setup timer and sleep mode .initialize(1 * 1000000); Timer1 // enter idle state (); idle} void loop(){ if (isMovement == true){ (PIN_LED, HIGH); digitalWrite(1000); delay(PIN_LED, LOW); digitalWrite(1000); delay} }
V tomto prevedení je možné vidieť ošetrenie externých prerušení. A to konkrétne level interrupt, ktorý reprezentuje tlačidlo a pin change interrupt, ktorý reprezentuje PIR senzor.
Low-Power Library
Mikrokontrolér často obsahuje aj súčasti, ktoré potrebujú osobitné nastavenia, ak chceme znížiť ich spotrebu energie. Jedná sa napríklad o:
- A/D prevodník
- analógový komparátor
- Brown-out detect
- 3 časovače
- Watch-dog timer
Tieto súčasti mikrokontroléra je možné vypínať a zapínať selektívne. Je to možné dosiahnuť pomocou registrov mikrokontroléra alebo pomocou volaní makier nachádzajúcich sa v knižnici
avr/power.h
. Napríklad pre vypnutie A/D prevodníka je možné zavolať makropower_adc_disable()
a pre jeho opätovné zapnutie zasa makropower_adc_enable()
.Existuje však knižnica s názvom Low-Power, ktorá zjednodušuje prácu s režimom spánku a umožňuje pred prechodom do spánku vypínať požadované komponenty s cieľom dosiahnutia vyššej úspory energie. Knižnica má tieto vlastnosti:
- podporuje všetky režimy spánku mikrokontroléra ATmega328P,
- umožňuje mikrokontrolér uspať na 15 ms, 30 ms, 60 ms, 120 ms, 250 ms, 500 ms, 1 s, 2 s, 4 s, 8 s, a na stálo,
- umožňuje vypnúť A/D prevodník,
- umožňuje vypnúť modul Brownout Detector
- vo vybraných režimoch spánku umožňuje vypnúť všetky časovače, USART0, TWI, a modul SPI
Knižnica sa používa prostredníctvom triedy
LowPower
, ktorá má niekoľko metód:idle()
,adcNoiseReduction()
,powerDown()
,powerSave()
,powerStandby()
apowerExtStandby()
. Každá z nich reprezentuje niektorý z režimov spánku mikrokontroléra. Pomocou parametrov týchto metód je možné nastaviť dĺžku strvania spánku ako aj zoznam súčastí, ktoré majú byť zapnuté alebo vypnuté.Príklad použitia ilustruje nasledujúci riadok kódu. Pomocou neho sa mikrokontrolér uspí na 8 sekúnd v režime Power Down, pričom moduly ADC a BOD budú vypnuté.
.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); LowPower