Režimy spánku modulu Arduino
Modul Arduino UNO běžící standardní rychlostí odebírá z USB nebo napájecího konektoru elektrický proud zhruba 45–50 mA. Při této spotřebě by vydržela běžná lithiová baterie s kapacitou 1000 mAh při troše štěstí ani 24 hodin. Pro projekty napájené z baterie, jako jsou například různé teploměry nebo dataloggery, to rozhodně není zrovna moc akceptovatelná doba. Pro bateriové aplikace zpravidla potřebujeme, aby naše zařízení běželo bez výměny baterie aspoň řádově týdny, nebo dokonce měsíce.
Řešením jak snížit spotřebu je využití tzv. režimu spánku. Většina moderních mikrokontrolérů je tímto režimem vybavena, tak proč se na něj nezaměřit a nevyzkoušet i u modulu Arduino. Přepnutím mikrokontroléru do některého z jeho stavů spánku (například do tzv. hlubokého spánku) můžete snížit spotřebu proudu až někam pod hranici 1 μA. To je proti původnímu aktivnímu stavu snížení více jak 50 000 násobné. V kombinaci s inteligentními strategiemi probouzení a napájení tak modulu můžeme prodloužit výdrž baterie až na námi požadované měsíce.
Připravujeme se na režim spánku
Než se podíváme na konkrétní ukázky kódů, je dobré pochopit, jak je to na modulu Arduino s jeho napájením. Jako ukázkový příklad si ukážeme modul Arduino UNO, které je napájené napětím 5 V.
Je třeba si uvědomit, že Arduino UNO je především celý modul, který má několik částí. Hlavní napájené části modulu tedy jsou:
- Mikrokontrolér ATmega328P: ~15 mA při standardním taktu 16 MHz
- USB-sériový čip (CH340/ATmega16U2): ~5–20 mA (a to i v nečinnosti!)
- LED signalizující napájení: ~3 mA
- Integrovaný 5V regulátor (pokud napájíme z 9V vstupu): klidový proud ~5 mA (plus tepelné ztráty)
Jistě hned vidíme, že už samotný USB čip a napájecí LED spotřebovávají mnohem více energie než samotný hlavní procesor ATmega328P pro svůj běh!
Pochopitelně pro seriózní projekty napájené bateriemi není Arduino UNO tou nejlepší volbou, ale podobný rozbor je třeba udělat při použití jakéhokoliv mikrokontroléru a podle toho zvolit ten správný. Hned nás tedy napadá, proč v nabídce platformy kupříkladu Arduino existují i moduly bez USB převodníku a bez LED signalizující zapnuté napájení.
- Doporučení pro stavbu:
- Pro skutečně úsporné projekty zapomeňme na Arduino UNO! Raději sáhněme po Arduino Pro Mini (3,3 V/8 MHz), které nemá žádný USB čip (programuje se přes levný externí USB-TTL převodník) a chybí mu i zbytečná napájecí LED dioda. V aktivním režimu má tento modul spotřebu asi jen ~4,5 mA a v režimu spánku dokonce padá na neuvěřitelných 0,36 μA! Projekt realizovaný na modulu Arduino Pro Mini (3,3 V/8 MHz) se tak stává ideální volbou pro projekty napájené z baterie. Naše zapojení pak může i na malou knoflíkovou baterii běžet docela dlouho.
Režimy spánku ATmega328P
Procesor ATmega328P (je použit v deskách Arduino UNO, Nano a Pro Mini) podporuje pět základních režimů spánku, přičemž každý z nich se liší rychlostí probuzení a flexibilitou zdroje probuzení. Následující tabulka představuje přehled a základní charakteristiky těchto režimů:
| Režim spánku | Proud (při 3,3 V) |
Zdroje probuzení | Poznámka |
|---|---|---|---|
Idle |
~1 mA | Jakékoli přerušení | Nejméně úsporný. Zastaví pouze CPU, ale veškeré periferie (časovače, sériová linka, SPI, TWI) mohou zůstat zapnuté. Vhodné, když potřebujeme okamžitou reakci. |
ADC Noise Reduction |
~0,9 mA | ADC dokončen, vybraná přerušení | Zastaví CPU, ale udržuje v chodu ADC převodník. Slouží k eliminaci šumu při přesném měření analogových hodnot. |
Power-down |
~0,36 μA | Externí INT, WDT, TWI adresa | Nejhlubší spánek (nejnižší spotřeba). Vypíná hlavní hodiny i oscilátor. Budit lze pouze přes Watchdog, externí přerušení (interrupt) nebo změnu stavu pinu (pin change). |
Power Save |
~1,6 μA | Externí INT, WDT, Časovač 2 | Podobný jako Power-down, ale umožňuje nechat běžet Timer2. Toho se využívá např. při připojení externího 32,768 kHz krystalu pro přesné měření času. |
Standby |
~0,8–1 mA | Externí INT, WDT, krystal | Funguje podobně jako Power-down, ale nechává běžet hlavní krystalový oscilátor. Probuzení procesoru je díky tomu extrémně rychlé (6 taktů/~0,375 μs), ale spotřeba je vyšší. |
Režim Power-down se nejčastěji používá pro maximální výdrž baterie, neboť zastaví všechny časovače kromě oscilátoru watchdog časovače, zastaví CPU a deaktivuje všechny periferie. Čip je v podstatě v režimu hibernace. Probudit ho můžeme externím přerušením na INT0/INT1, změnou úrovně na pinu (s přerušeními změnou pinu) nebo pomocí watchdog časovače.
Knihovna pro režimy spánku
Psát kód přímo přes nízkoúrovňové registry AVR je vcelku nepříjemné. Musíme poměrně detailně znát význam jednotlivých registrů (SMCR, PRR, MCUCR atd.) a jejich složitější nastavování bývá častým zdrojem chyb. Použití hotové knihovny, která tuto práci ulehčí pomocí intuitivních příkazů, proto výrazně zrychlí a zjednoduší vývoj celého projektu.
Pro 8bitové mikrokontroléry AVR (jako má Arduino UNO, Nano nebo Pro Mini) je skvělou volbou prověřená knihovna LowPower od autora Rocket Scream. Tu lze snadno stáhnout a nainstalovat z GitHubu: https://
Knihovna LowPower
Knihovna LowPower je jednou z nejoblíbenějších a nejvšestrannějších knihoven pro správu napájení a snižování spotřeby u mikrokontrolérů Arduino (především těch založených na čipech AVR, jako jsou ATmega328P, ATmega2560 a další). Knihovna využívá různé režimy spánku, které nabízí samotný hardware zmíněných mikrokontrolérů, a zabaluje je do velmi jednoduchého a přehledného API.
Následující tabulka ukazuje přehled jednotlivých režimů spánku, které knihovna umožňuje nastavit a přehled příkazů, jakými jich lze dosáhnout.
| Režim spánku | Příkaz v knihovně |
|---|---|
| Idle | LowPower.idle(period, ...) |
| ADC Noise Reduction | LowPower.adcNoiseReduction(...) |
| Power-down | LowPower.powerDown(period, adc, bod) |
| Power-save | LowPower.powerSave(period, adc, timer2, bod) |
| Standby | LowPower.standby(period, adc, bod) |
| Extended Standby*) | LowPower.powerExtStandby(...) |
*) Kombinace režimu Standby a Power-save – udržuje aktivní externí oscilátor a navíc umožňuje provoz Timeru 2.
Základní příklady používání knihovny
Režim Idle
Pokud potřebujeme, aby během spánku dál fungovaly některé periferie (například sériová komunikace nebo určité časovače), použijeme režim Idle. U něj se navíc v parametrech specifikuje, co všechno chcete vypnout/zapnout:
- Syntaxe příkazu pro režim spánku Idle:
LowPower.idle( period, adc, timer2, timer1, timer0, spi, usart0, twi)
kde mají jednotlivé parametry následující význam:
period (Doba trvání spánku) – určuje, na jak dlouho integrovaný Watchdog časovač (WDT) procesor uspí.
SLEEP_15MS,SLEEP_30MS,SLEEP_60MS,SLEEP_120MS,SLEEP_250MS,SLEEP_500MS,SLEEP_1S,SLEEP_2S,SLEEP_4S,SLEEP_8S(8 sekund je maximum AVR Watchdogu)SLEEP_FOREVER(vypne Watchdog; procesor spí trvale, dokud ho nevzbudí externí přerušení/signál)
adc (A/D převodník) – řídí napájení a taktování analogového převodníku.
ADC_OFF– vypne převodník (doporučeno pro maximální úsporu energie)ADC_ON– ponechá převodník aktivní (nutné proadcNoise)Reduction
timer2 (Časovač/čítač 2) – asynchronní čítač využívaný převážně pro čítání reálného času (RTC) s externím krystalem 32,768 kHz.
TIMER2_OFF– vypne Timer 2 během spánkuTIMER2_ON– ponechá Timer 2 v provozu (umožní budit čip přetečením čítače)
timer1 (TIMER1_OFF/TIMER1_ON) – 16bitový časovač č. 1
timer0 (TIMER0_OFF/TIMER0_ON) – 8bitový časovač č. 0 (vypnutí zastaví funkce millis() a micros())
spi (SPI_OFF/SPI_ON) – zapnutí/vypnutí rozhraní SPI
usart0 (USART0_OFF/USART0_ON) – zapnutí/vypnutí sériové linky (hardware UART)
twi (TWI_OFF/TWI_ON) – zapnutí/vypnutí sběrnice I2C/TWI
Ukázkový program:
#include <LowPower.h>
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("Jdu spát na 1s!");
Serial.flush(); // DŮLEŽITÉ: Počkej, než se odeslou data přes sériový port!
// Uvedení do Idle režimu na 1 sekundu, přičemž vypneme zbytečné periferie pro úsporu
LowPower.idle(SLEEP_1S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART0_OFF, TWI_OFF);
// Zde pokračuje program po probuzení
}
- Poznámka:
- Pokud používáme sériový port, před uspáním je vždy třeba zavolat
Serial.flush, abychom zajistili, že se vyrovnávací paměť sériového přenosu vyprázdnila. Pokud modul uspíme během přenosu bajtů, výstup se nevypíše celý a UART se může zablokovat.
Režim ADC Noise Reduction
Smyslem režimu ADC Noise Reduction (u mikrokontrolérů ATmega328P) je uspat procesor přesně na těch několik mikrosekund, během kterých probíhá samotný analogový převod. Když běžně čtete hodnotu z analogového pinu (např. z čidla teploty nebo fotorezistoru), digitální obvody a běžící procesor (CPU) vytvářejí elektrický šum, který může způsobit kolísání naměřených hodnot (skákání čísel). V tomto režimu se tedy CPU pozastaví, ale analogově-digitální převodník (ADC) zůstane plně aktivní, čímž se šum radikálně sníží.
Pro skutečnou redukci šumu musí procesor usnout přesně v okamžiku, kdy ADC převodník měří napětí, a probudit se automaticky ve chvíli, kdy je měření hotové
- Syntaxe příkazu pro režim spánku:
LowPower.adcNoise Reduction( period, adc, timer2)
kde použité parametry a jejich hodnoty byly popsány u předešlého režimu.
- Poznámka k automatickému spuštění převodu:
- V ukázkovém kódu ručně nenastavujeme bit
ADSC(Start Conversion) pro spuštění analogového převodu, což by mohlo vyvolat dojem, že v programu spuštění chybí. U mikrokontroléru ATmega328P se však převod spouští automaticky, pokud je aktivován A/D převodník i jeho přerušení (ADENaADIE), samotný přechod procesoru do spánku v režimu ADC Noise Reduction spustí analogový převod přímo na úrovni hardwaru. Převodník tak měří napětí v plném tichu bez rušení běžícího CPU a po dokončení měření vyvolá přerušeníADC_vect, které procesor okamžitě probudí.
Následující kód ukazuje, jak režim zapnout těsně před měřením citlivé analogové hodnoty:
#include <LowPower.h>
#include <avr/interrupt.h>
const int analogPin = A0;
// Přerušení, které po dokončení převodu probudí CPU ze spánku
ISR(ADC_vect) {}
uint16_t readADCWithLowPower(uint8_t pin) {
uint8_t channel = (pin >= 14) ? pin - 14 : pin;
// 1. Výběr pinu a reference napětí (AVcc)
ADMUX = (1 << REFS0) | (channel & 0x07);
delayMicroseconds(100); // Ustálení napětí
// 2. Zapnutí ADC a jeho přerušení (ADIE)
ADCSRA |= (1 << ADEN) | (1 << ADIE);
// 3. Knihovna LowPower uspí CPU do SLEEP_MODE_ADC.
// V tento moment HW automaticky spustí převod a vypne takt CPU.
LowPower.adcNoiseReduction(SLEEP_FOREVER, ADC_ON, TIMER2_OFF);
// --- CPU spí ~104 μs, ADC měří v tichu. Přerušení vzbudí CPU. ---
// 4. Úklid a přečtení výsledku z HW registru
ADCSRA &= ~(1 << ADIE);
return ADC;
}
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("Měřím v režimu ADC Noise Reduction...");
Serial.flush();
uint16_t rawValue = readADCWithLowPower(analogPin);
float voltage = rawValue * (5.0 / 1023.0);
Serial.print("Naměřeno: ");
Serial.print(rawValue);
Serial.print(" | Napětí: ");
Serial.print(voltage);
Serial.println(" V");
delay(2000);
}
Zde nás asi ukázkový program trochu vyděsil, kromě využití knihovny, zde manipulujeme s hodnotami registrů a používáme přerušení.
Arduino analogRead() nepodporuje spánek – standardní funkce analogRead() z core Arduina spouští převod a čeká na jeho dokončení
ve smyčce za plného běhu CPU.
Aby vstup do spánku ADC Noise Reduction automaticky spustil analogový převod a po jeho dokončení procesor probudil, musí mít ADC povolené přerušení (ADIE = 1) a definovanou obsluhu přerušení (ISR(ADC_vect)). Knihovna LowPower ale ADC nenastavuje. Funkce v knihovně pouze nastaví spánkový registr MCU na režim ADC Noise Reduction a spustí instrukci sleep. Nastavení analogového pinu, referenčního napětí ani zapnutí přerušení převodníku neprovádí. Pokud zavoláme pouze LowPower. bez nastavení registrů ADC, procesor usne, ale protože není aktivováno ADC přerušení ani spuštěn převod, procesor „vytuhne“ ve spánku navždy.
Pokud chceme použít knihovnu LowPower a zároveň docílit reálného měření během spánku, je minimální nastavení ADC registrů před zavoláním knihovny nezbytné.
Režim Power-down
Režim powerDown() zastaví hlavní oscilátor CPU, vypne všechny interní čítače/časovače, sběrnice (SPI, I2C, UART) i analogový převodník. Spotřeba samotného čipu ATmega328P klesne na úroveň cca 0,1 μA až 5 μA (Nejhlubší spánek).
Předáním parametrů ADC_OFF a BOD_OFF zamezíte jakémukoliv parazitnímu odběru analogové části a detektoru podpětí během spánku.
- Syntaxe příkazu pro režim spánku:
LowPower.powerDown( period, adc, bod)
Kromě výše popsaných parametrů, zde vidíme nový parametr bod:
bod (Brown-Out Detector) – Detektor poklesu napájecího napětí pod bezpečnou mez.
BOD_OFF– softwarově vypne BOD během spánku (ušetří dalších cca 20–25 μA)BOD_ON– ponechá BOD zapnutý (vhodné, pokud hrozí vybití baterie pod nestabilní úroveň)
Probuzení časovačem
V prvním příkladu si ukážeme pravidelné uspání na 8 sekund:
#include <LowPower.h>
const int ledPin = LED_BUILTIN; // Vestavěná LED (D13 na Uno/Nano)
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
Serial.println("Inicializace dokončena. Start smyčky...");
Serial.flush();
}
void loop() {
// Vizualizace probuzení – krátké bliknutí LED
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
Serial.println("Uspávám procesor (Power-down) na 8 sekund...");
Serial.flush(); // DŮLEŽITÉ: Vyčistí sériovou frontu před usnutím, jinak se zpráva neodesle celá
// Uvedení mikrokontroléru do nejhlubšího režimu spánku (Power-down)
// 1. parametr: Doba spánku (SLEEP_8S je maximum pro Watchdog časovač)
// 2. parametr: ADC_OFF (vypne A/D převodník pro dosažení minimální spotřeby)
// 3. parametr: BOD_OFF (vypne Brown-Out Detector – detekci poklesu napájení)
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
// Po 8 sekundách vyprší Watchdog timer a kód pokračuje přesně na tomto místě
Serial.println("Probudil jsem se!");
Serial.flush();
}
Časové omezení: Integrovaný Watchdog časovač (WDT) u mikročipů AVR umí mikrokontrolér probudit po maximálně 8 sekundách (SLEEP_8S). Pokud potřebujete spát déle (např. 1 minutu), zavolá se LowPower. ve for cyklu 7× za sebou.
void sleepMinutes(int minutes) {
// Each call sleeps ~8 seconds
// minutes * 60 / 8 = number of 8s periods
int cycles = (minutes * 60) / 8;
for (int i = 0; i < cycles; i++) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
}
Trvalý spánek a probuzení tlačítkem (Ext. Interrupt)
Pokud nechceme budit procesor periodicky přes Watchdog, ale např. stiskem tlačítka na pinu D2 (INT0), použijeme následující program:
#include <LowPower.h>
const int wakeUpPin = 2; // Pin D2 (INT0)
void wakeUpISR() {
// Přerušovací rutina – stačí prázdná, slouží pouze k probuzení CPU
}
void setup() {
pinMode(wakeUpPin, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
Serial.println("Jdu spát navždy, dokud nestiskneš tlačítko na D2...");
Serial.flush();
// Připojení přerušení na pin D2 (při stisku tlačítka k GND / LOW)
attachInterrupt(digitalPinToInterrupt(wakeUpPin), wakeUpISR, LOW);
// Uspání bez Watchdogu – procesor čeká na externí signál
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
// Odpojení přerušení po probuzení, aby se nevolalo opakovaně za běhu
detachInterrupt(digitalPinToInterrupt(wakeUpPin));
Serial.println("Probudil mě stisk tlačítka!");
delay(1000);
}
Režim Power-save
V režimu Power-down je zastaveno úplně vše kromě příslušných externích přerušení a Watchdogu. V režimu Power-save zůstává jako jediný vnitřní periferní modul v provozu Timer2 (pokud předáme parametr TIMER2_ON). Tento režim se primárně používá v aplikacích, kde je na piny TOSC1/TOSC2 mikrokontroléru (u ATmega328P piny PB6/PB7) připojen externí hodinový krystal 32,768 kHz. Timer2 díky němu tiká i během spánku procesoru, počítá přesný čas (hodiny, minuty, sekundy) a spotřeba procesoru přitom zůstává extrémně nízká (~1–2 μA).
#include <LowPower.h>
const int ledPin = LED_BUILTIN; // Vestavěná LED (D13)
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
Serial.println("Inicializace Power-save režimu...");
Serial.flush();
}
void loop() {
// Vizualizace probuzení – krátké bliknutí LED
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
Serial.println("Uspávám procesor (Power-save) na 8 sekund...");
Serial.flush(); // Vyčistí sériový buffer před usnutím
// Uvedení mikrokontroléru do režimu Power-save
// 1. parametr: Doba spánku přes Watchdog (SLEEP_8S, SLEEP_4S, SLEEP_FOREVER...)
// 2. parametr: ADC_OFF (vypne A/D převodník)
// 3. parametr: BOD_OFF (vypne detekci poklesu napětí BOD)
// 4. parametr: TIMER2_ON / TIMER2_OFF (ponechá nebo vypne asynchronní Časovač 2)
LowPower.powerSave(SLEEP_8S, ADC_OFF, BOD_OFF, TIMER2_ON);
// Po probuzení kód pokračuje zde
Serial.println("Probudil jsem se z Power-save!");
Serial.flush();
}
Volba TIMER2_OFF vs. TIMER2_ON:
- Pokud nastavíme
TIMER2_ON, čítač Timer2 běží na pozadí a jeho přetečení (overflow) může mikrokontrolér kdykoliv probudit. - Pokud nastavení přepneme na
TIMER2_OFF, režim Power-save se z hlediska spotřeby i chování fakticky chová stejně jako režim Power-down.
Režimy Standby a Extended Standby
Režimy Standby a Extended Standby představují kompromis mezi úsporou energie a rychlostí probuzení. U většiny spánkových režimů (jako Power-down nebo Power-save) se hlavní krystalový oscilátor úplně vypne. Po probuzení procesoru pak trvá až 16 milisekund (cca 16 000 hodinových taktů), než se krystal opětně rozkmitá a stabilizuje.
Standby režimy tento problém řeší tím, že hlavní krystalový oscilátor nechávají neustále běžet:
- Standby (
SLEEP_): Vypne CPU, periferie i Timer2, ale ponechá běžet hlavní oscilátor. Probuzení procesoru je díky tomu extrémně rychlé – trvá pouze 6 hodinových taktů (cca 0,375 μs při 16 MHz). Spotřeba je vyšší než u Power-down (cca 0,8–1 mA), ale odezva na přerušení je okamžitá.MODE_ STANDBY - Extended Standby (
SLEEP_): Funguje stejně jako Standby (hlavní oscilátor běží), ale navíc ponechává v provozu asynchronní Timer2 (např. pro čítání reálného času z externího hodinového krystalu 32,768 kHz). Spojuje tedy běh RTC hodin s okamžitou reakcí na přerušení.MODE_ EXT_ STANDBY
Ukázkový kód pro režim Standby
#include <LowPower.h>
const int ledPin = LED_BUILTIN;
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
Serial.println("Start aplikace – režim Standby");
Serial.flush();
}
void loop() {
// Vizualizace běhu CPU
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
Serial.println("Uspávám procesor do Standby na 8 sekund...");
Serial.flush();
// Režim Standby
// 1. parametr: Doba spánku (SLEEP_8S)
// 2. parametr: ADC_OFF (vypne A/D převodník)
// 3. parametr: BOD_OFF (vypne detekci poklesu napětí BOD)
LowPower.standby(SLEEP_8S, ADC_OFF, BOD_OFF);
// Po probuzení pokračuje kód ihned bez čekání na stabilizaci krystalu (6 taktů)
Serial.println("Probudil jsem se okamžitě!");
Serial.flush();
}
Ukázkový kód pro režim Extended Standby – nyní jen vyměníme v předešlém programu řádek:
// Režim Standby
// 1. parametr: Doba spánku (SLEEP_8S)
// 2. parametr: ADC_OFF (vypne A/D převodník)
// 3. parametr: BOD_OFF (vypne detekci poklesu napětí BOD)
LowPower.standby(SLEEP_8S, ADC_OFF, BOD_OFF);
Za následující:
// Režim Extended Standby
// 1. parametr: Doba spánku (SLEEP_8S)
// 2. parametr: ADC_OFF (vypne A/D převodník)
// 3. parametr: BOD_OFF (vypne detekci poklesu napětí BOD)
// 4. parametr: TIMER2_ON (ponechá v provozu Časovač 2)
LowPower.powerExtStandby(SLEEP_8S, ADC_OFF, BOD_OFF, TIMER2_ON);
Praktická ukázka:
Nízkoenergetický datalogger teploty
Využití režimu spánku si ukážeme na projektu nízkopříkonového záznamníku teploty s použitím modulu Arduino Pro Mini a senzoru DS18B20. Zatímco předešlé kódy jsme mohli testovat na libovolném modulu Arduino (s procesorem ATmega), nyní je tento kód určen především pro Arduino Pro Mini (3,3 V/8 MHz). Kód bude pochopitelně fungovat i na modulu Arduino UNO, ale nepočítejme pak s takovou výdrží jako u modulu Pro Mini.
Inteligentní řízení napájení senzoru pomocí tranzistoru
Samo o sobě uspání procesoru mikrokontroléru do režimu Power-down k dosažení maximální výdrže baterie nestačí. Pokud do obvodu zapojíme externí periferie – například digitální teploměr DS18B20, displej nebo paměťový modul – tyto součástky spotřebovávají elektrický proud neustále, i když procesor spí a žádná data neměří. Klidový odběr samotného čidla DS18B20 sice dosahuje jen několika mikroampér, ale v součtu s ostatními prvky může spolehlivě zmařit veškerou úsporu získanou uspáním mikrokontroléru.
Nejefektivnějším řešením je hardwarové odpojování napájení senzoru v době, kdy procesor spí. Napájení VCC senzoru nepřipojujeme přímo na trvalou napájecí větev (3,3 V nebo 5 V), ale napájíme jej přes spínací tranzistor (např. malý P-FET nebo NPN/PNP bipolární tranzistor), jehož bázi či hradlo řídíme digitálním výstupním pinem Arduina. V případě teplotního čidla Dallas DS18B20, která odebírá proud asi 1,5 mA, však lze tranzistor vynechat a napájet toto čidlo přímo z digitálního výstupu.
Následující obrázek ukazuje možné elektronické zapojení našeho dataloggeru:
Napájení teplotního senzoru DS18B20 je tedy řešeno přímo výstupní úrovní digitálního výstupu D5 – jeho stav budeme ovládádat přímo v programu:
digitalWrite(
digitalWrite(
Výhody navrženého řešení:
- nulové napájení senzoru během spánku,
- bezpečně vypnutý senzor po resetu mikrokontroléru,
- zachování jednoduché logiky programu (
HIGH= zapnout,LOW= vypnout),
Díky tomuto zapojení je aktivní pouze krátké období měření, zatímco po většinu času zůstává nejen mikrokontrolér, ale i samotný teplotní senzor ve skutečně beznapěťovém stavu. To výrazně prodlužuje provozní dobu zařízení napájeného z baterie.
Parazitní napájení přes datovou linku
Při vypínání napájení senzoru je třeba dát pozor na skrytý efekt tzv. parazitního napájení. Pokud pinem D5 odpojíme napájení VCC senzoru, ale na datovém pinu (OneWire – pin D4) zůstane úroveň HIGH (např. díky internímu nebo externímu pull-up rezistoru), elektrický proud začne protékat z datového pinu přes interní ochranné diody senzoru přímo do jeho vnitřních obvodů. Senzor tak ve skutečnosti nikdy nevypne, nadále odebírá proud z datového pinu a znehodnocuje úsporný režim. Jak tomuto jevu zabránit? Před každým odpojením napájení senzoru a následným usnutím procesoru musíme v kódu ošetřit i datový pin – buď jej softwarově přepneme do stavu LOW, nebo jej konfigurujeme jako vstup bez pull-up rezistoru (pinMode(). Teprve tím datovou linku zcela odpojíme od napětí.
Optimalizace doby převodu senzoru (9bitové rozlišení)
Proč dále v kódu měníme rozlišení senzoru z 12 na 9 bitů? Ve výchozím nastavení pracuje senzor DS18B20 v 12bitovém rozlišení (s rozlišovací schopností 0,0625 °C). Jedno převodní měření však v tomto režimu trvá dlouhých 750 ms. Jelikož je knihovní funkce request blokující, mikrokontrolér musí po celou tuto dobu čekat v plně aktivním stavu s nejvyšší spotřebou.
Pomocí příkazu sensors. snížíme rozlišení senzoru na 9 bitů (s rozlišením 0,5 °C). Doba převodu teploty klesne ze 750 ms na pouhých ~94 ms (tedy téměř na osminu původního času). Celková doba bdění procesoru – včetně stabilizace napájení (50 ms) a odeslání dat po sériové lince – tak bezpečně klesne pod 200 ms (0,2 s).
Zkrácením aktivní fáze z ~850 ms na 200 ms snížíme nábojovou spotřebu v bdělém stavu na čtvrtinu. Pro běžné měření teploty (např. v místnosti či venku) je rozlišovací schopnost 0,5 °C více než dostačující, zatímco získaná úspora energie je pro výdrž baterie zcela zásadní.
Následující ukázkový program se probouzí každých 8 sekund, načítá teplotu a znovu se přepíná do režimu spánku. Naměřenou hodnotu zde pouze vypisuje na sériový port, ale v reálném nasazení bychom ji spíše ukládali například na SD kartu nebo paměti EEPROM.
Postup při měření v průběhu programu:
- Probuzení procesoru ze spánku.
- Nastavení úrovně
HIGHna pinuD5, tím přivedení napájení na VCC senzoru. - Krátká pauza (cca 50 ms) pro stabilizaci napájecího napětí čidla.
- Provedení měření a načtení dat přes rozhraní OneWire.
- Vypnutí napájení senzoru úrovní
LOWna pinechD5aD4. - Uspání procesoru.
#include <LowPower.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 4 // Datový pin pro OneWire sběrnici
#define SENSOR_POWER 5 // Řídicí pin tranzistoru (spíná VCC senzoru)
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup() {
Serial.begin(9600);
// Konfigurace pinu pro řízení tranzistoru
pinMode(SENSOR_POWER, OUTPUT);
digitalWrite(SENSOR_POWER, LOW); // Senzor je na začátku vypnutý (tranzistor rozpojen)
// Bezpečnostní nastavení datového pinu v klidovém stavu
pinMode(ONE_WIRE_BUS, INPUT);
}
float readTemperature() {
// 1. ZAPNUTÍ NAPÁJENÍ SENZORU
digitalWrite(SENSOR_POWER, HIGH);
delay(50); // Krátká pauza na stabilizaci napájecího napětí čidla
// 2. INICIALIZACE A NASTAVENÍ SENZORU
sensors.begin();
// Nastavení 9bitového rozlišení: zkrátí dobu převodu ze 750 ms na jen ~94 ms!
// Výrazně zkracuje aktivní dobu procesoru a šetří kapacitu baterie.
sensors.setResolution(9);
// 3. PROVEDENÍ MĚŘENÍ A NAČTENÍ TEPLOTY
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
// 4. VYPNUTÍ NAPÁJENÍ SENZORU
digitalWrite(SENSOR_POWER, LOW);
// 5. OŠETŘENÍ PARAZITNÍHO NAPÁJENÍ
// Datový pin stáhneme na LOW, aby z něj přes ochranné diody čidla netekl proud
pinMode(ONE_WIRE_BUS, OUTPUT);
digitalWrite(ONE_WIRE_BUS, LOW);
return temp;
}
void loop() {
// Provedení měření teploty
float temp = readTemperature();
// Výpis naměřené hodnoty na sériovou linku
Serial.print("Teplota: ");
Serial.print(temp);
Serial.println(" °C");
// Důležité: Vyčištění vyrovnávací paměti UARTu před usnutím,
// aby se data stihla kompletně odeslat
Serial.flush();
// Zde by následovalo uložení na SD kartu / EEPROM nebo odeslání dat přes Lora/NRF24
// USNUTÍ PROCESORU NA 8 SEKUND
// Využíváme nejhlubší spánek (Power-down) s vypnutím ADC a BOD
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
Odhad spotřeby a výdrže baterie
Podívejme se na reálný výpočet spotřeby našeho dataloggeru při nahraní kódu do desky Arduino Pro Mini (3,3 V/8 MHz) napájené z akumulátoru s kapacitou 1000 mAh:
Aktivní režim (bdění): Díky 9bitovému rozlišení čidla a stabilizaci trvá aktivní fáze procesoru přibližně 0,2 s (200 ms) s odběrem 4,5 mA.
Spotřeba v aktivním stavu = 4,5 mA × 0,2 s= 0,9 mAs
Režim spánku (Power-down): Zbytek osmivteřinového cyklu (7,8 s) procesor spí se spotřebou cca 0,5 μA (0,0005 mA).
Spotřeba ve spánku = 0,0005 mA × 7,8 s = 0,0039 mAs
Celková spotřeba za jeden cyklus (8 sekund): 0,9 mAs + 0,0039 mAs = 0,9039 mAs
Přepočteno na miliampérhodiny (1 mAh = 3600 mAs):
0,9039 mAs/3600 ≈ 0,00025108 mAh/cyklus (8 s)
Odhad celkové výdrže baterie (1000 mAh):
1000 mAh/0,00025108 mAh ≈ 3 982 758 cyklů
Každý cyklus trvá 8 sekund, což dává celkový čas:
3 982 758 × 8 s = 31 862 064 s ≈ 8 850 hodin ≈ 369 dní
Při dodržení těchto výše uvedených optimalizací dokáže i malý 1000 mAh akumulátor napájet senzorový uzel přes celý jeden rok (i po započtení drobné režie pro uložení dat).
Od teorie k realitě:
Výpočet roční výdrže na obyčejný 1000 mAh akumulátor jasně ukazuje sílu systematické optimalizace. Dosažení hranice jednoho roku však v reálném světě vyžaduje myslet i na faktory, které žádná teoretická rovnice plně nezachytí:
- Každý akumulátor (ať už Li-Ion, LiPo nebo běžné AA články) postupně ztrácí náboj i v nezatíženém stavu. U kvalitních článků jde o jednotky procent ročně, u méně kvalitních či starších akumulátorů však může jít o znatelně vyšší ztráty.
- Pokud plánujeme datalogger umístit do venkovního prostředí, počítejme s tím, že mráz výrazně snižuje využitelnou kapacitu baterie a zvyšuje její vnitřní odpor.
- V našem výpočtu jsme uvažovali pouze samotné měření a odeslání po sériové lince. Pokud do cyklu přidáte zápis na SD kartu, uložení do paměti EEPROM nebo bezdrátový přenos přes modul LoRa či nRF24L01+, musíte k aktivní fázi přičíst nábojový odběr těchto vysílačů (které si při vysílání mohou vzít i 30–120 mA po dobu několika desítek milisekund).
Závěr
Přechod od standardního provozu mikrokontroléru k efektivnímu využití úsporných režimů spánku představuje zásadní krok k realizaci dlouhodobě udržitelných bateriových projektů. Extrémně nízké spotřeby však nelze dosáhnout pouze jednou „magickou“ funkcí v kódu, ale těsnou souhrou čtyř vrstev:
- volbou vhodného hardwaru (např. Arduino Pro Mini 3,3 V bez napájecí LED a USB převodníku s odběrem 0,36 μA),
- správného režimu spánku (Power-down s vypnutým
ADCaBOD), - hardwarovým odpojováním periferií tranzistorem
- a optimalizací logiky kódu (zkrácením doby bdění).
Pokud z této logiky vynecháte některý prvek, baterie se místo za rok vybije už za pár dní. Jak však ukazuje příklad našeho dataloggeru, při dodržení všech zásad dokáže obyčejný 1000 mAh akumulátor napájet senzorový uzel přes celý jeden rok. Důsledná optimalizace tak proměňuje původně „žravé“ Arduino z pouhého prototypovacího nástroje v plnohodnotné a spolehlivé autonomní zařízení pro dlouhodobý provoz v terénu.
| [1] | JAIN, Jayesh. Arduino Sleep Mode: Reduce Power for Battery Projects. Online. Zbotic. 2026. Dostupné z: https:// [cit. 2026-11-10]. |
