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

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í 3040 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ť len SLEEP_MODE_IDLE, SLEEP_MODE_ADC, SLEEP_MODE_PWR_SAVE, SLEEP_MODE_STANDBY alebo SLEEP_MODE_PWR_DOWN
  • sleep_mode() - makro na prechod do režimu spánku spolu s nastavením bitu SE (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. Makro sleep_mode() totiž najprv bit SE nastaví (volanie sleep_enable()), následne mikrokontrolér uspí (volanie sleep_cpu()) a po zobudení zasa bit SE vyčistí (volanie sleep_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(){
    pinMode(LED_BUILTIN, OUTPUT);
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}

void loop(){
    // blink
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);

    // sleep
    sleep_mode();

    // unreachable code
    digitalWrite(LED_BUILTIN, LOW);
    delay(500);
}

[!WARNING]

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á.

Waking the Microcontroller with External Interrupts

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 troch stavov. Zmení sa však spôsob prechodov medzi jednotlivými savtmi.

Rovnako tak sa nezmení ani schéma zapojenia - bude identická, ako je 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(){
    isMovement = false;
    digitalWrite(PIN_LED, LOW);
    digitalWrite(LED_BUILTIN, LOW);

    // reatach interrupts
    detachInterrupt(digitalPinToInterrupt(PIN_BTN));
    attachInterrupt(digitalPinToInterrupt(PIN_PIR), watch, RISING);
    Timer1.detachInterrupt();

    // go to sleep
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    interrupts();
    sleep_mode();
}

void tick(){
    countdown--;

    if(countdown == 0){
        alarm();
    }

    // go to sleep
    interrupts();
    sleep_mode();
}

void watch(){
    // update state
    digitalWrite(PIN_LED, HIGH);

    // reatach interrupts
    set_sleep_mode(SLEEP_MODE_ADC);
    attachInterrupt(digitalPinToInterrupt(PIN_PIR), idle, FALLING);
    countdown = 10;
    Timer1.attachInterrupt(tick);
    Timer1.restart();

    // go to sleep
    interrupts();
    sleep_mode();
}

void alarm(){
    // update state
    digitalWrite(PIN_LED, HIGH);
    isMovement = true;

    // reatach interrupts
    Timer1.detachInterrupt();
    detachInterrupt(digitalPinToInterrupt(PIN_PIR));
    attachInterrupt(digitalPinToInterrupt(PIN_BTN), idle, LOW);
}

void setup(){
    // set pin modes
    pinMode(PIN_LED, OUTPUT);
    pinMode(PIN_PIR, INPUT);
    pinMode(PIN_BTN, INPUT_PULLUP);

    // setup timer and sleep mode
    Timer1.initialize(1 * 1000000);

    // enter idle state
    idle();
}

void loop(){
    if (isMovement == true){
        digitalWrite(PIN_LED, HIGH);
        delay(1000);
        digitalWrite(PIN_LED, LOW);
        delay(1000);
    }
}

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ť makro power_adc_disable() a pre jeho opätovné zapnutie zasa makro power_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() a powerExtStandby(). 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é.

LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);

Measuring Power in Sleep Mode

results matching ""

    No results matching ""