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.

ATmega328P Frequency vs Supply Current (5V)
Image 14 - ATmega328P Frequency vs Supply Current (5V)

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.

`CLKPR` Register
Image 15 - `CLKPR` Register

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 CLKPS0CLKPS3 (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:

  1. Globálne vypnúť prerušenia volaním makra noInterrupts().

  2. Nastaviť hodnotu bit-u CLKPCE na 1 a všetky ostatné bity registra CLKPR na 0.

  3. Následne je potrebné zapísať hodnotu bitov CLKPS, ktorá zodpovedá príslušnému deliču Clock Division Factor.

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

CLKPR = _BV(CLKPCE);

a

CLKPR = 0x80;

sú ekvivalentné.

results matching ""

    No results matching ""