Reducing Clock Frequency of Microcontroller
Ďalší zo spôsobov, ako znížiť spotrebu energie v zariadení a predĺžiť tak životnosť batérie, je znížiť frekvenciu mikrokontroléra. Nie vždy je totiž potrebné, aby mikrokontrolér pracoval na plnej frekvencii. Preto je vždy dobré zvážiť, či obetovať zvýšenie životnosti batérie za zníženie počtu vykonateľných inštrukcií za sekundu.
Mikrokontrolér ATmega 328P používa na generovanie hodinových cyklov externý oscilátor o frekvencii 16 MHz. Vzťah medzi aktuálnou pracovnou frekvenciou mikrokontroléra a množstvom odoberanej energie je možné vidieť na obrázku XXX. Ako je možné vidieť, znížením frekvencie je možné aj strojnásobiť životnosť batérie.

Po znížení hodinovej frekvencie však netreba zabudnúť na to, že táto zmena sa nedotkne len frekvencie samotného mikrokontroléra, ale aj všetkých synchrónnych periférií. To znamená, že zmena frekvencie sa dotkne aj volania funkcií delay()
alebo millis()
. Rovnako tak sa dotkne rýchlosti V/V komunikácie (napr. na sériovej linke), rýchlosti A/D prevodníku a podobne.
Pri zmene hodinovej frekvencie musí byť vypnuté ošetrovanie prerušení. Tým bude zabezpečené, že operácia zápisu, resp. zmeny hodinovej frekvencie, nebude ničím prerušená. Vhodné miesto pre zmenu frekvencie sa preto javí funkcia setup()
, kde dôjde k nastaveniu hodinovej frekvencie ešte pred spustením samotného programu.
Zmenu frekvencie je možné na mikrokontroléri ATMEL ATmega 328P zmeniť delením hodnoty registra Clock Prescale Register, skrátene CLKPR
. Jeho zmenou je možné znížiť hodnotu frekvencie hodín a tým pádom aj znížiť spotrebu energie. Jeho štruktúra sa nachádza na obrázku XXX.

Najvyšší bit registra CLKPR
nesie označenie CLKPCE
- Clock Prescaler Change Enable. Ak sa má zmeniť frekvencia mikrokontroléra, treba ho nastaviť na hodnotu 1 a všetky ostatné bity na hodnotu 0. K jeho vynulovaniu dôjde automaticky buď po 4 cykloch alebo po zápise CLKPS
bitov.
Kombináciou bitov CLKPS0
až CLKPS3
(Clock Prescaler Select Bits) je možné nastaviť tzv. Clock Division Factor. Ten určuje, koľkonásobne sa zníži frekvencia mikrokontroléra. Ich zmenu je možné vykonať kedykoľvek počas behu programu. Aj keď sú k dispozícii 4 bity, ktoré umožňujú 16 rozličných kombinácií, prípustných je len 8. Možné kombinácie sú zobrazené v tabuľke XXX.
CLKPS3 | CLKPS2 | CLKPS1 | CLKPS0 | Clock Division Factor | Frequency |
---|---|---|---|---|---|
0 |
0 |
0 |
0 |
1 |
16 MHz |
0 |
0 |
0 |
1 |
2 |
8 MHz |
0 |
0 |
1 |
0 |
4 |
4 MHz |
0 |
0 |
1 |
1 |
8 |
2 MHz |
0 |
1 |
0 |
0 |
16 |
1 MHz |
0 |
1 |
0 |
1 |
32 |
500 kHz |
0 |
1 |
1 |
0 |
64 |
250 kHz |
0 |
1 |
1 |
1 |
128 |
125 kHz |
1 |
0 |
0 |
0 |
256 |
62.5 kHz |
Pre zmenu frekvencie mikrokontroléra ATmega 328P je teda potrebné vykonať tieto kroky:
Globálne vypnúť prerušenia volaním makra
noInterrupts()
.Nastaviť hodnotu bit-u
CLKPCE
na 1 a všetky ostatné bity registraCLKPR
na 0.Následne je potrebné zapísať hodnotu bitov
CLKPS
, ktorá zodpovedá príslušnému deliču Clock Division Factor.Globálne prerušenia zapnúť volaním makra
interrupts()
.
Pre prezentáciu zmeny frekvencie mikrokontroléra, použijeme samotné Arduino Uno a štandardný príklad Blink. Budeme teda blikať zabudovanou LED diódou v pravidelných 1 sekundových intervaloch. Zdrojový kód riešenia sa nachádza vo výpise XXX.
#include <Arduino.h>
void setup(){
pinMode(LED_BUILTIN, OUTPUT);
}
void loop(){
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
Po preložení a spustení bude LED dióda 1 sekundu svietiť a následne na 1 sekundu zhasne.
Následne upravíme funkciu setup()
tak, že v nej znížime frekvenciu mikrokontroléra na 2 MHz - nastavíme hodnotu Clock Division Factor na 8. Za tým účelom je potrebné nastaviť hodnotu bitov CLKPS0
a CLKPS1
na 1, ktoré sú spolu s CLKPCE
dostupné ako makrá.
void setup(){
noInterrupts();
CLKPR = _BV(CLKPCE); // 0x80
CLKPR = _BV(CLKPS0 | CLKPS1); // 0x03
interrupts();
pinMode(LED_BUILTIN, OUTPUT);
}
Totou úpravou sa znížila frekvencia mikrokontroléra na 2 MHz. Tentokrát celý cyklus zasvietenia a zhasnutia nebude trvať 2 sekundy, ale 4, pretože súčasne so znížením frekvencie došlo k ovplyvneniu správania funkcií delay()
a millis()
.
- TODO: vypocet
Ak by sme na koniec funkcie loop()
pridali riadok na vypísanie počtu milisekúnd od spustenia programu, videli by sme stále rovnaké hodnoty, či už by sme frekvenciu zmenili alebo nie. To znamená, že táto hodnota je závislá od nastavenej frekvencie. Tomuto problému sa ale dá vyhnúť nastavením makra F_CPU
na správnu frekvenciu v čase prekladu.
[!NOTE]
V kóde je použité aj makro
_BV()
, ktoré prevedie číslo bitu, ktoré dostane ako parameter, na zodpovedajúcu číselnú hodnotu (byte). Takže zápisyCLKPR = _BV(CLKPCE);
a
CLKPR = 0x80;
sú ekvivalentné.