Week 04
interrupts, timers, sleep mode
Annoucements
(slide) homepage
- Jekyll + GitLab pages + CI
- je to lepšie a lepšie
(slide) mattermost
(slide) hack košice
- iný typ hackathonu ako tie, ktoré ste mali možnosť zažiť
- medzinárodná (študentská) účasť
- priestor pre to, aby ste sa naozaj niečo nové naučili
(slide) Namakaný deň 2019
Handling the Internal Interrupts with Arduino
(slide) 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.
(slide) Mikrokontrolér
ATmega328P obsahuje 3 časovače označené ako
TIMER0
, TIMER1
a TIMER2
.
TIMER0
a TIMER2
sú 8 bitové, zatiaľ
čo TIMER2
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.
(slide) 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()
a micros()
. TIMER1
je
zasa možné nájsť v knižnici Servo.h
a TIMER2
sa používa pri generovaní zvuku pomocou funkcie tone()
.
Funkcia analogWrite()
využíva každý časovač, ale každý pre
rozličné piny.
(slide) 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 |
(slide) 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
(slide) 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 bolo do knižnice zahrnuté
aj prerušenie timer overflow a iné vlastnosti.
(slide) 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.
Putting Your Device to Sleep
(slide) 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?
(slide) 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.
(slide) 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.
(slide) 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ý.
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
)
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í
[!NOTE]
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čidlo
RESET
.
#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 bol definovaný 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
bude, že pokus o preprogramovanie mikrokontroléra v stave spánku bude
neú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á.