Skip to main content

3.4 Hodiny reálneho času

Pri práci s mikrokontrolérmi je často potrebné poznať reálny dátum a čas (a pokiaľ možno, veľmi presný). Táto potreba je síce v koncepte internetu vecí často potlačená - predovšetkým v režime fog alebo cloud computing - no rozhodne nie je na škodu. Dostupnosť a plynutie času riešia hodiny reálneho času (RTC - Real Time Clock).

Interné hodiny síce môžu byť implementované priamo v MCU (nie je to samozrejmosť), no aby fungovali aj po odpojení napájania, musela by byť prítomná batéria. Plnohodnotné riešenie RTC teda predstavuje samostatný obvod s malou batériou - externé hodiny. Takéto riešenie poznáme aj zo základných dosiek počítačov. Vývojové dosky mikrokontrolérov nezvyknú mať externé hodiny, medzi výnimky patrí zariadenie M5StickC Plus.

2.10 časovač.webp

Interné hodiny RTC

Mikrokontroléry ESP32 majú k dispozícii interné hodiny, ktoré si čas udržia aj pri reštarte zariadenia, no po odstavení napájania sa čas stratí a vráti sa na polnoc 1. januára roku 2000. Preto je potrebné interné hodiny nastaviť po každom spustení zariadenia:

  • a) manuálne (čo je len zriedka realizovateľné),
  • b) z externého modulu RTC (ak je prítomný),
  • c) z časového NTP servera (ak je dostupná sieť).

Náš firmvér pre M5Stick pri každom štarte nastaví interné hodiny z externého modulu RTC, pokiaľ má realistický dátum.

Interné hodiny sú v MicroPython dostupné cez objekt RTC z modulu machine. Konštruktor tohoto objektu neprijíma žiadne parametre. Hoci dokumentácia uvádza viaceré objektové funkcie, implementovaná je len funkcia datetime(), ktorá nastaví dátum a čas - jej jediným parametrom je tupla v tvare (rok, mesiac, deň, None, hodina, minúta, sekunda, mikrosekunda). Štvrtým parametrom je v skutočnosti deň týždňa, ale pri nastavovaní hodín nemá zmysel a možno ho vynechať uvedením None.

Nastavenie interných hodín teda môžeme realizovať príkazom:

  • RTC().datetime(({rok}, {mesiac}, {deň}, None, {hodina}, {minúta}, {sekunda}, 0))

Pre získanie času z interných hodín máme k dispozícii viaceré funkcie z modulu time:

  • time(): vráti aktuálny čas v podobe uplynutých sekúnd od polnoci 1. januára 2000;
  • time_ns(): vráti aktuálny čas v podobe uplynutých nanosekúnd od polnoci 1. januára 2000;
  • gmtime(): vráti aktuálny čas v podobe tuply v tvare (rok, mesiac, deň, hodina, minúta, sekunda, deň týždňa, deň roka) - je v neutrálnej časovej zóne UTC (GMT);
  • localtime(): funguje rovnako ako gmtime(), ale mala by vrátiť čas v miestnej časovej zóne - časové zóny však nie sú v MicroPython implementované.
from time import gmtime

def Cas(c):
   return "{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(c[0], c[1], c[2], c[3], c[4], c[5])

print("Interné hodiny:", Cas(gmtime()))

Časové zóny

Časové zóny a letný čas môžu značne komplikovať výpočty s časovými údajmi. Najlepším riešením je nastaviť interné hodiny na neutrálny čas UTC, s týmto časom aj pracovať a časovú zónu (spolu so spracovaním letného času) riešiť až pri vypisovaní času.

Ukážka vlastnej funkcie localtime(), ktorá vráti čas v našej časovej zóne CET (GMT+1), s prihliadnutím na letný čas CEST (GMT+2):

def localtime(s = None):
    from time import time, mktime, gmtime   
    if s is None: s = time()
    rok = gmtime(s)[0]
    letny = list(gmtime(mktime((rok, 3, 31, 2, 0, 0, None, None))))
    letny[2] -= (letny[6] + 1) % 7
    zimny = list(gmtime(mktime((rok, 10, 31, 2, 0, 0, None, None))))
    zimny[2] -= (zimny[6] + 1) % 7
    letny[6:8] = zimny[6:8] = (None, None)
    s += 3600 # UTC+1
    if (mktime(letny) < s < mktime(zimny)):
        s += 3600
    return gmtime(s)

print("Interné hodiny miestnej časovej zóny:", Cas(localtime()))

Externé hodiny RTC

Zariadenie M5StickC Plus je vybavené externým modulom RTC BM8563, teda externými hodinami, ktoré bežia aj po vypnutí zariadenia, až do vybitia batérie. Keďže sa jedná o klon RTC PCF8563, môžeme využiť knižnicu preň. Hodiny sú pripojené cez zbernicu I²C. V našom firmvéri je v module M5Stick už všetko nachystané, objekt hodín je dostupný pod menom M5Stick.rtc.

Objekt poskytuje funkcie pre externé hodiny:

  • datetime(): vráti aktuálny čas v podobe tuply v tvare (rok, mesiac, deň, hodina, minúta, sekunda, deň týždňa) - je vhodné nastaviť ho interným hodinám (viď vyššie);
  • datetime({čas}): nastaví čas, zadaný v podobe tuply v tvare (rok, mesiac, deň, hodina, minúta, sekunda, deň týždňa) - deň týždňa je v rozsahu 0 (pondelok) až 6 (nedeľa).

Aj čas externých hodín by mal byť v neutrálnej časovej zóne UTC.

# zobrazenie externých hodín
import M5Stick
cas_ext = M5Stick.rtc.datetime()
print("Externé hodiny:", Cas(cas_ext))

# nastavenie interných hodín z externých hodín:
from machine import RTC
print("Nastavujem interné hodiny…")
RTC().datetime(cas_ext[:3] + (None,) + cas_ext[3:])
print("Interné hodiny:", Cas(gmtime()))

# zobrazenie času v miestnej časovej zóne (treba funkciu localtime)
print("Interné hodiny miestne:", Cas(localtime()))