Időzítők, számlálók
A fejezet tartalma:- Az időzítés szerepe a beágyazott rendszerekben
- Időzítők/számlálók a MKL25Z128VLK4 mikrovezérlőben
- A Timer objektumosztály
- A Timeout objektumosztály
- A Ticker objektumosztály
- Az RTC kezelése a Time programkönyvtár használatával
- A WakeUp objektumosztály
Az időzítés szerepe a beágyazott rendszerekben
A beágyazott rendszerek időben kell, hogy reagáljanak a bekövetkező eseményekre, vagy előre megadott ütemezés szerint kel, hogy végezzék feladataikat (pl. adatgyűjtés/adatmegjelenítés azonos időközönként). Ebből következően a beágyazott rendszereknek képeseknek kell lennie az alábbiakra:- Időtartam mérése
- Idő-alapú események generálása, ami lehet egyszeri vagy ismétlődő
- Megfelelő sebességgel reagálni az előre nem meghatározható időben bekövetkező eseményekre
Ebből következik, hogy szükségünk van olyan eszközökre és módszerekre, amelyek lehetővé teszik a hatékony idő-alapú tevékenység végzését. Főbb elemei ennek az eszköztárnak az előző fejezetben tárgyalt megszakítások valamint az időzítők/számlálók, amelyekkel ebben a fejezetben foglalkozunk. A számláló (counter) olyan digitális áramkör, amellyel feszültségimpulzusokat tudunk leszámlálni. Ha a leszámlálandó impulzusok nem külső forrásból származnak, hanem ismert, állandó frekvenciájú jelet vezetünk a számláló bemenetére, akkor pedig időzítőről (timer) beszélünk, amely lehetővé teszi számunkra az idő mérését, illetve a feladatok ütemezését.
Ütemezést tulajdonképpen már használtunk a legelső LED villogtató projektünknél is, amelyben wait(0.2) függvényhívásokkal arra utasítottuk a mikrovezérlőt, hogy 0.2 másodpercig várakozzon a LED állapotváltások között. Az ilyen várakoztatás roppant egyszerűen, akár üres programciklusokkal is megvalósítható, ám a blokkoló jellege miatt nem hatékony. Komolyabb programjainkban nyilván azt szeretnénk majd, hogy a mikrovezérlő a várakozások során más feladattal is foglalkozhasson, s az időmérés a háttérben történjen. Ezzel el is érkeztünk a hardveres számlálók és időzítők használatához...
Számlálókat gyakran használnak a digitális áramkörökben. Ezek többnyire sorbakötött bistabil billenőáramkörök, melyek mindegyike egy-egy bitnyi információt tárol. Egy n-bites számláló 2n-1 állapotot képes felvenni. Például az alábbi ábrán látható 8 bites számláló 0000 0000-tól 1111 1111-ig, azaz 0-tól 255-ig számol.
![](images/timers/counter.png)
1. ábra: Egyszerű 8-bites számláló
Ha a számláló bemenetére ismert és stabil frekvenciájú jelet vezetünk, akkor a számlálónk időzítőként használható. Például 1 MHz-es órajel (periódusidő = 1 µs) esetén a számlálónk mikroszekundumokat számlál.
Időzítők/számlálók a MKL25Z128VLK4 mikrovezérlőben
A Freescale KL25 Sub_Family Reference Manual szerint az MKL25Z128VLK4 mikrovezérlő az alábbi számlálókkal, illetve időzítőkkel rendelkezik:- Systick 24-bites (vissza)számláló, amely az ARM Cortex-M mikrovezérlő mag része (a Systick számláló megvalósítása az ARM Cortex-M0 és M0+ magú mikrovezérlőknél opcionális, de a legtöbb gyártó beépíti). Többnyire ezt a számlálót használják az RTOS operációs rendszerek a feladatok ütemezéséhez.
- Timer0, Timer1, Timer2 16-bites számlálók, amelyekhez 2-6 db impulzus-szélesség modulációra (PWM) használható csatorna is tartozik. Ezekkel a számlálókkal a PWM című fejezetben már találkoztunk.
- Periodic Interrupt Timer (PIT) modul,
ami 2 db 32 bites időzítővel rendelkezik, amelyek egy 64 bites
időzítővé is összekapcsolhatók. A PIT
modul eredetileg periodikus megszakítások előállítására szolgál, de az mbed környezetben a két számlálót
sorbakötve a bekapcsolás, illetve az utolsó RESET óta eltelt idő
mikroszekundumos felbontású mérésére használjuk (az us_ticker() függvény ahhoz hasonlóan
működik, ahogy az Arduino környezetben a millis() függvény, csak ott
milliszekundumos felbontással mérjük az eltelt időt). Az mbed környezeteben a wait(), wait_ms(), wait_us()
függvények is a PIT modult
használó us_ticker() függvény
felhasználásával végzik az eltelt idő ellenőrzését a megadott
késleltetési idő kivárása közben.
- Low-Power Timer (LPTMR) 16-bites időzítő/számláló. Az LPTMR kisfogyasztású időzítő egyik legfontosabb jellemzője, hogy mindegyik energiatakarékos módban üzemképes marad, s külső események számlálására vagy belső órajellel időzítésre használható. A 16-bites számláló bemenetéhez előszámlálót vagy zajszűrőt is konfigurálhatunk. Az előosztás mértéke kettő hatványai szerinti, 2 - 65536 közötti szám lehet. Az mbed környezetben az LPTMR időzítő foglalt, a Ticker (periodikus megszakítás), illetve a WakeUp (felébresztés "mélyalvás" energiatakarékos módból) objektumosztályok használják.
- Real-Time Clock (RTC)
modul, melyben található 32-bites másodperc számláló, 16-bites
előszámláló, 16-bites időkompenzációs regiszter és egy 32-bites
regiszter az ébresztés beállítására. A FRDM-KL25Z
kártya esetén az RTC órajelét az OpenSDA
áramkör biztosítja, s az MKL25Z128VLK4
mikrovezérlő PTC1 kivezetését (RTC_CLKIN) lefoglalja. Az RTC modul
óráját mbed környezetben a
beépített rtc_time API
függvények segítségével írhatjuk/olvashatjuk.
A Timer objektumosztály
A Timer objektumosztály segítségével absztrakt időmérőket hozhatunk létre, amellyel pl. a két esemény között eltelt időt mérhetjük meg, mikroszekundumos felbontással.1. táblázat: A Timer objektumosztály tagfüggvényei
Függvény |
Használat |
---|---|
Timer név |
Létrehoz egy "név" nevű absztrakt Timer objektumot. |
start() |
Elindítja az időmérést |
stop() |
Megállítja az időmérést |
reset() |
Nullázza az időmérőt |
read() |
Másodpercekben adja meg az
eltelt időt. |
read_ms() | Ezredmásodpercekben adja meg az eltelt időt. |
read_us() | Milliomod másodpercekben adja meg az eltelt időt. |
Mintapélda: Reakcióidő mérése Timer használatával
Az alábbi programban, amely Albertas Galin: "Reaction_timer" c. programjának átirata, a Timer absztrakt időzítőt stopperként használjuk, s egy LED felgyulladása és a válaszként lenyomott nyomógomb bekapcsolása között eltelt időt mérjük vele (a felhasználó reakcióideje). Az eredményt az alapértelmezett soros porton keresztül íratjuk ki.Hardver követelmények:
- FRDM-KL25Z kártya
- A D3 (PTA12) bemenet és a GND közé egy nyomógombot kell kötni az alábbi ábra szerint.
![](images/digital_io/led_button.png)
2. ábra: A nyomógomb bekötése
1. lista: A 08_reaction_time/main.cpp program listája
#include "mbed.h"
DigitalOut myled(LED_GREEN); //define LED
DigitalIn mybutton(D3,PullUp); //define pushbutton input with pull-up
Timer t; //define timer
int x; //x for random number storage
int main() {
myled = 1; //LED is initially off
printf("\r\nReaction test!\r\n");
printf("Push the button when the LED is on!\r\n");
while(1) {
while(!mybutton); //wait for button release
x=rand()%2000; //generate random number 0-2000
wait_ms(1000+x); //wait random time between 1 and 3 seconds
t.start(); //start the timer
myled=0; //LED on
while(mybutton); //wait for press
t.stop(); //stop the timer
myled=1; //LED off
wait_ms(20); //debounce delay
printf("The time taken was %f seconds\r\n", t.read());
t.reset(); //reset the timer
}
}
A nyomógomb bemenetet belső felhúzású módba konfiguráljuk, így nem kell
külső felhúzó ellenállást kötni a D3 (PTA12) bemenetre. A while(1)
feltételvizsgálattal kezdődő végtelen ciklus elején a nyomógomb
felengedésére történő várakozás megakadályozza a lassú felengedésből,
vagy az eleve lenyomva tartásból adódó téves időmérést. A LED
felkapcsolása előtt egy (ál)véletlen hosszúságú (1000-3000 ms
időtartamú) várakozás következik, majd elindítjuk a stoppert. A
nyomógomb lenyomásakor leállítjuk az időmérést és lekapcsoljuk a
LED-et, majd kiíratjuk az eredményt. Az újabb mérési ciklus megkezdése
előtt nulláznunk kell a stoppert a t.reset()
függvényhívással.![](images/timers/08_reaction_time.png)
3. ábra: A 08_reaction_time program futási eredménye
A Timeout objektumosztály
A Timeout objektumosztály segítségével ébresztőórához hasonló időmérőt hozhatunk létre, amellyel adott idő elteltével visszahívási (callback) függvényt aktiválhatunk, a főprogram futását megszakítva. Mivel a visszahívási függvény programmegszakítási szinten aktiválódik, ügyelnünk kell rá, hogy a visszahívási függvény ne tartalmazzon blokkoló várakozást, terjedelmes adatfeldolgozást, printf kiíratást, memória allokációt. Megfontolandó az RTOS Timer használata a Timeout helyett, mert akkor nem megszakítási szinten történik a visszahívás.2. táblázat: A Timeout objektumosztály tagfüggvényei
Függvény |
Használat |
---|---|
Timeout név |
Létrehoz egy "név" nevű Timeout objektumot. |
attach(*fptr,time) |
A Timeout objektumhoz
rendel egy visszahívási függvényt és megadja a visszahívási időt. Az
időt lebegőpontos formátumban, másodpercben adjuk meg. |
attach_us(*fptr,time) |
A Timeout objektumhoz rendel egy visszahívási függvényt és megadja a visszahívási időt. Az időt unsigned int formátumban, mikroszekundumokban adjuk meg. |
detach() |
Megszünteti a visszahívási
függvény hozzárendelését az időzítőhöz |
Mintapélda: LED állapotváltás Timeout használatával
Az alábbi programban, amely az mbed Handbook Timeout_HelloWorld mintapéldája, a Timeout absztrakt időzítőt arra használjuk, hogy egy visszahívási függvény segítségével adott idő eltelte után LED2 állapotát átváltsuk, miközben a főprogram végtelen ciklusában LED1 villogtatása zajlik folyamatosan.Hardver követelmények:
- FRDM-KL25Z kártya
#include "mbed.h"
Timeout flipper;
DigitalOut led1(LED1); // LED_RED
DigitalOut led2(LED2); // LED_GREEN
void flip() { // callback function
led2 = !led2; // flip state of LED_GREEN
}
int main() {
led2 = 1;
flipper.attach(&flip, 2.0); // setup flipper to call flip after 2 seconds
// spin in a main loop. flipper will interrupt it to call flip
while(1) {
led1 = !led1; // blink LED_RED
wait(0.2); // by 2.5 Hz (0.2s ON, 0.2s OFF)
}
}
A program elindításakor (bekapcsolás, vagy RESET után) először csak LED1 (a piros LED) villog 2.5 Hz
frekvenciával. Kb. 2 másodperc után LED2
(a zöld LED) is bekapcsol a flip függvény meghívásának hatására, s az
újabb RESET-ig folyamatosan világít.A Ticker objektumosztály
A Ticker objektumosztály segítségével olyan "ébresztőórát" hozhatunk létre, amellyel periodikusan, adott időközönként aktiválhatjuk az objektumhoz rendelt visszahívási (callback) függvényt, a főprogram futását megszakítva. Mivel a visszahívási függvény programmegszakítási szinten aktiválódik, ügyelnünk kell rá, hogy a visszahívási függvény ne tartalmazzon blokkoló várakozást, terjedelmes adatfeldolgozást, printf kiíratást, memória allokációt.Nem árulunk el nagy titkot azzal, ha elmondjuk, hogy a Timeout és a Ticker objektumosztály lényegében megegyezik, kizárólag a visszahívási függvény aktiválásában térnek el: Timeout esetén csak egyszer történik aktiválás, a Ticker esetében pedig minden aktiváláskor "újra felhúzzuk az ébresztőt", ezért periodikusan ismétlődik az aktiválás.
A különbséget megfigyelhetjük, ha a 2. listában bemutatott programban a Timeout flipper; sort kicseréljük erre: Ticker flipper;
3. táblázat: A Ticker objektumosztály tagfüggvényei
Függvény |
Használat |
---|---|
Ticker név |
Létrehoz egy "név" nevű Ticker objektumot. |
attach(*fptr,time) |
A Ticker objektumhoz
rendel egy visszahívási függvényt és megadja a visszahívási időt. Az
időt lebegőpontos formátumban, másodpercben adjuk meg. |
attach_us(*fptr,time) |
A Ticker objektumhoz rendel egy visszahívási függvényt és megadja a visszahívási időt. Az időt unsigned int formátumban, mikroszekundumokban adjuk meg. |
detach() |
Megszünteti a visszahívási
függvény hozzárendelését az időzítőhöz |
Mintapélda: Nyomógomb pergésmentesítése Ticker használatával
Az alábbi programban egy Ticker időzítő segítségével periodikusan mintavételezzük egy nyomógomb állapotát. Ha a mintavételezések közötti időtartam nagyobb, mint a kontaktusok pergési ideje (10-15 ms), akkor a mintavételezéssel megoldhatjuk a nyomógomb pergésmentesítését. A nyomógombbal egy LED-et kapcsolgatunk ki és be. A nyomógomb kezelés vonatkozásban az alábbi program a Programmegszakítások fejezetben található 07_button_interrupt mintaprogram javított változatának tekinthető.Hardver követelmények:
- FRDM-KL25Z kártya
- A D3 (PTA12) bemenet és
a GND közé egy nyomógombot
kell kötni a 2. ábra szerint.
#include "mbed.h"
DigitalIn button(D3,PullUp); // Pusbutton input
DigitalOut led(LED_BLUE); // LED output (the blue LED)
Ticker sampler; // Ticker for button state sampling
volatile uint8_t button_state = 1; // Initially released
void button_check()
{
button_state = (button_state<<1) | (button & 1); // shift in button state
if((button_state & 3)==2) { // Check for H -> L transition
led = !led; // Switch LED state
}
}
int main()
{
led = 1; // LED off
sampler.attach(&button_check,0.02); // sample button state in each 20 ms
while (true) {
wait(1); // do nothing
}
}
A nyomógomb figyelésére a D3
kivezetést digitális bemenetként konfiguráljuk és bekapcsoljuk a belső
felhúzást. A bemenet állapotát 20 ms-onként mintavételezzük, s jobbról
beléptetjük a button_state
változó legalsó bitjébe (1: a
gomb felengedve, 0: a gomb
lenyomva). Amikor lenyomás történik, akkor a button_state változó utolsó két
bitjén '10'
bitkombinációnak kell lennie: (button_state & 3)==2). A fenti
programban ehhez az eseményhez rendeltük a LED állapotának
átkapcsolását.Az RTC kezelése a Time
programkönyvtár használatával
Az RTC valósidejű óra kezeléséhez az alapértelmezett mbed API nem tartalmaz C++
objektumosztályt. Az alábbiakban bemutatott, hiányosan dokumentált Time
programkönyvtár valójában a standard C könyvtárből örökölt C
függvényekből áll, melyekhez a céláramkörök RTC hardverének kezelésére
(regiszterek beállítása, illetve kiolvasása) szolgáló C függvények
társulnak. Az aktuális idő az 1970. január 1. óta eltelt másodperceket jelenti (UNIX timestamp), a tárolása time_t "timestamp" (időbélyeg) típusú változókban történik, ami valójában uint32_t típust jelent. Az idő kiíratáshoz, emberi léptékű kezeléshez a tm sruktúra típust használjuk, amelyben külön-külön változókban szerepel az év, a hónap, a nap, az óra, a perc és a másodpercek.
A Time programkönyvtár szűkszavú leírása mellett néhány egyszerű mintapélda is található. Egy részletesebb, de elavult leírás itt található.
3. táblázat: A Time programkönyvtár függvényei
Függvény |
Használat |
---|---|
time(NULL) |
Az aktuális idő kiolvasása. A
visszatérési érték timestamp típusú |
set_time(time_t t) |
Az aktuális idő beállítása |
mktime(struct tm * t) |
Egy tm struktúra átalakítása timestamp formátumra. A paraméter tm struktúrára mutató pointer, a vissztérési érték timestamp típus. |
localtime(time_t
* t) |
Egy timestamp átalakítása tm struktúrába (a visszatérési érték pointer!) |
ctime(time_t
* t) |
Egy timestamp olvasható szöveggé
történő konverziója. Pl. “Wed Oct 28 11:35:37 2009\n” |
sfrtime(char
* buffer, size_t max, char * format, struct tm * t) |
Egy tm struktúra testreszabható
formátumú szöveggé alakítása |
time - Az aktuális idő kiolvasása a targetáramkör RTC moduljából, amelyet előzőleg a set_time() segítségével állíthatunk be. Az "aktuális idő" az 1970. január 1. óta eltelt másodperceket jelenti (UNIX timestamp).
#include "mbed.h"
int main() {
set_time(1256729737); // Set RTC time to Wed, 28 Oct 2009 11:35:37
while(1) {
time_t seconds = time(NULL);
printf("Time as seconds since January 1, 1970 = %d\n", seconds);
wait(1);
}
}
set_time - az aktuális idő beállítása
#include "mbed.h"
int main() {
set_time(1256729737); // Set time to Wed, 28 Oct 2009 11:35:37
}
mktime - Egy tm struktúrát időbélyeggé alakít, mely az 1970. január 1. óta eltelt másodperceket jelenti (UNIX timestamp). Egyúttal a tm struktúra tm_wday (a hét napja) és tm_yday (az év napja) elemeit is aktualizálja. Ügyeljünk rá, hogy az évszámokat 1900-hoz képest kell megadni, s a hónapok számozása 0-val kezdődik!
#include "mbed.h"
int main() {
// setup time structure for Wed, 28 Oct 2009 11:35:37
struct tm t;
t.tm_sec = 37; // 0-59
t.tm_min = 35; // 0-59
t.tm_hour = 11; // 0-23
t.tm_mday = 28; // 1-31
t.tm_mon = 9; // 0-11
t.tm_year = 109; // year since 1900
// convert to timestamp and display (1256729737)
time_t seconds = mktime(&t);
printf("Time as seconds since January 1, 1970 = %d\n", seconds);
}
localtime - egy time_t típusú időbélyeg értékét egy (statikusan allokált) tm stuktúrába konvertálja.
#include "mbed.h"
int main() {
time_t seconds = 1256729737;
struct tm *t = localtime(&seconds);
}
ctime - egy time_t időbélyeg formában megadott időpontot olvasható formátumú dátum/idő szöveggé alakít. Az eredmény ilyen formátumú lesz: “Wed Oct 28 11:35:37 2009\n”.
#include "mbed.h"
int main() {
time_t seconds = time(NULL);
printf("Time as a string = %s", ctime(&seconds));
}
strftime - egy tm struktúra formájában megadott időpont testreszabható formátumú szöveggé alakítása. Az sfrtime függvény abban különbözik a ctime függvénytől, hogy time_t helyett tm stuktúrát vár, s nem kötött formátumú az eredmény, hanem általunk megadott formátumú.
#include "mbed.h"
int main() {
time_t seconds = time(NULL);
char buffer[32];
strftime(buffer, 32, "%I:%M %p\n", localtime(&seconds));
printf("Time as a formatted string = %s", buffer);
}
A formátum megadásához az alábbi szövegelemeket használhatjuk:4. táblázat: Az
sfrtime() függvénynél használható formátumelemek
listája
%S | Second (másodperc 00-59) |
%M |
Minute (perc 00-59) |
%H |
Hour (óra 0-23) |
%d |
Day (nap 01-31) |
%m |
Month (hónap 01-12) |
%Y/%y |
Year (év 2009, illetve 09
formátumban) |
%A/%a |
Weekday name (hét napjának neve
Monday, illetve Mon formátumban) |
%B/%b |
Month name (hónap neve January,
illeve Jan formátumban) |
%I |
12 Hour format (12 órás kijelzés
00-12) |
%p |
AM vagy PM |
%X |
Time (idő 14:55:02 formátumban) |
%x |
Date (dátum 02/05/09 formában
February 5, 2009 esetén) |
Mintapélda: Az RTC kipróbálása
A Time programkönyvtár mintaprogramjának segítségével kipróbáljuk az MKL25Z128VLK4 mikrovezérlő RTC modulját. A program semmi hasznos dolgot nem csinál, csupán az alábbi lépéseket próbáljuk ki vele:- RTC beállítása egy adott időpontra (itt 28 Oct 2009 11:35:37) a set_time() függvény segyítségével.
- Az aktuális idő kiolvasása a time() függvénnyel.
- Dátum és idő kiíratása kötött formátumban a ctime() függvény használatával.
- Idő kiíratása általunk előírt formátumban a localtime() és sfrtime() függvények használatával
Hardver követelmények:
- FRDM-KL25Z kártya
#include "mbed.h"
int main()
{
set_time(1256729737); // Set RTC time to Wed, 28 Oct 2009 11:35:37
while(1) {
time_t seconds = time(NULL);
printf("Time as seconds since January 1, 1970 = %d\n", seconds);
printf("Time as a basic string = %s", ctime(&seconds));
char buffer[32];
strftime(buffer, 32, "%I:%M %p\n", localtime(&seconds));
printf("Time as a custom formatted string = %s", buffer);
wait(1);
}
}
A program futási eredménye az alábbi ábrán látható:![](images/timers/08_rtc_test.png)
4. ábra: A 08_rtc_test program futási eredménye
Mintapélda: az RTC használata
Az előző programban csak egy önkényesen választott időpontra állítottuk be az RTC óráját. Az alábbi programmal tetszés szerinti időpontot, tehát a tényleges időt is megadhatjuk a soros porton keresztül. Sajnos, a FRDM-KL25Z kártya RTC órája csak korlátozottan használható (nincs sem telepes póttápegysége sem saját órejel generátora, hogy a kártya kikapcsolt állapotában is mérje az időt), de az alábbi programmal legalább beállítástól kikapcsolásig nyomon követhetjük az idő múlását. A kiíratásokhoz nyissunk egy terminálablakot és kapcsolódjunk az OpenSDA virtuális soros portjához az alapértelmezett formátummal és sebességgel (8N1, 9600 bps)!Megjegyzés: Az alábbi mintapélda megírásához sokat merítettünk a limchonghan blogján közzétett Drift Corrected DS1307 Real Time Clock programból.
Az RTC beállításához egy TYYMMDDhhmmss parancsot kell kiküldenünk a terminálablakból, ahol:
T - a kötelező parancsbetű (T mint Time)
YY - az évszám utolsó két jegye (2016-ban ez 16)
MM - a hónap sorszáma (Január esetében 01)
DD - a nap (01 - 31 közötti szám)
hh - az óra (00 - 23 közötti szám)
mm - a perc (00 - 59 közötti szám)
ss - a másodperc (00 - 59 közötti szám)
Hardver követelmények:
- FRDM-KL25Z kártya
#include "mbed.h"
Serial pc(USBTX,USBRX); //UART0 via OpenSDA
DigitalOut myled(LED1);
Ticker myticker;
time_t mytime;
volatile uint8_t myflag =0;
void processSerialCommand();
void setflag(void)
{
myflag = 1;
}
int main()
{
set_time(1451736661);
myticker.attach(&setflag,5);
while(1) {
if(pc.readable()) {
processSerialCommand();
}
if(myflag) {
mytime = time(NULL);
pc.printf("RTC time: %s\r\n",ctime(&mytime));
myflag = 0;
}
}
}
void processSerialCommand()
{
char c = pc.getc();
switch(c) {
case 'T':
// Command to set RTC time
// Command format: TYYMMDDHHMMSS
// Example: 2012 Oct 21 1:23pm is T121021132300
struct tm tme;
time_t newTime;
// Parse incomming 12 ASCII charaters into time_t
// no error checking for numeric values in YYMDDHHMMSS fields, so be careful!
c = pc.getc();
tme.tm_year = c - '0';
c = pc.getc();
tme.tm_year = 10*tme.tm_year;
tme.tm_year += c-'0';
tme.tm_year += 100; //Years are counted from 1900!
c = pc.getc();
tme.tm_mon = c - '0';
c = pc.getc();
tme.tm_mon = 10*tme.tm_mon;
tme.tm_mon += c-'0'-1; //corrected by -1 due to a stupid error
c = pc.getc();
tme.tm_mday = c - '0';
c = pc.getc();
tme.tm_mday = 10*tme.tm_mday;
tme.tm_mday += c-'0';
c = pc.getc();
tme.tm_hour = c - '0';
c = pc.getc();
tme.tm_hour = 10*tme.tm_hour;
tme.tm_hour += c-'0';
c = pc.getc();
tme.tm_min = c - '0';
c = pc.getc();
tme.tm_min = 10*tme.tm_min;
tme.tm_min += c-'0';
c = pc.getc();
tme.tm_sec = c - '0';
c = pc.getc();
tme.tm_sec = 10*tme.tm_sec;
tme.tm_sec += c-'0';
newTime = mktime(&tme);
set_time(newTime);
pc.printf("RTC set to: %s\r\n",ctime(&newTime));
}
while(pc.readable()) {
pc.getc(); // clear serial buffer
}
}
A program futási eredménye az alábbi ábrán látható. A kép alsó sorában
a beírt parancs is látható, melynek hatására a pirossal aláhúzott
válaszüzenet jelent meg.![](images/timers/08_rtc_example.png)
5. ábra: A 08_rtc_example program futási eredménye
A WakeUp objektumosztály
Többé-kevésbé az időzítők témaköréhaz tartozik az Erik Olieman által írt WakeUp objektumosztály is, amely az LPTMR időzítő segítségével előre beállítható idő eltelével felébreszti a mikrovezérlőt az energiatakarékos "mélyalvás" üzemmódból. Ennek különösen telepes (elem vagy akkumulátor) táplálás esetén van jelentősége, hiszen ha tétlen állapotban lekapcsoljuk a mikrovezérlőt, jelentősen csökkenthetjük az energiaigényt, s akkor ugyanazzal az elemmel/akkumulátorral hosszabb üzemidőt érhetünk el.5. táblázat: A WakeUp objektumosztály tagfüggvényei
Függvény |
Használat |
---|---|
set(time) |
Beállítja az időzítést az egész
másodpercekben megadott időre |
set_ms(time) |
Beállítja az időzítést az
ezredmásodpercekben megadott időre |
attach(*fptr) |
Visszahívási függvényt rendel az
időzítőhöz. Ha csak ébreszteni akarjuk az MCU-t, akkor nincs szükségünk
erre a funkcióra! |
calibrate() |
A főoszcillátorhoz kalibrálja az
LPTMR óráját. Figyelem: a kalibrálás100 ms blokkoló várakozással jár! |
Mintapélda: WakeUp használata
Az alábbi programban egy LED-et villogtatunk úgy, hogy a LED kikapcsolt állapotában a mikrovezérlőt is "mélyalvás" állapotba helyezzük, amelyből a WakeUp segítségével ébresztjük fel, az időzítés letelte után. "Mélyalvás" állapotban az időzítők közül csak az LPTMR működik, ezért a WakeUp objektumosztály is ezt használja.A 08_wakeup program lényegében Erik Olieman WakeUp mintaprogramja, minimális változtatásokkal. A program LED1-et (a FRDM-KL25Z kártyán ez LED_RED-et jelenti) 2 másodpercig kikapcsolt, majd 1 másodpercig bekapcsolt állapotban tartja. A program lefordításához a WakeUp programkönyvtárat importálni kellett, s a program elején a WakeUp.h fejléc állományt be kellett csatolni.
Hardver követelmények:
- FRDM-KL25Z kártya
#include "mbed.h"
#include "WakeUp.h"
DigitalOut myled(LED1); //LED_RED
int main() {
//The low-power oscillator can be quite inaccurate on some targets
//this function calibrates it against the main clock
WakeUp::calibrate();
while(1) {
myled = 1; //Switch LED off
WakeUp::set_ms(2000); //Set wakeup time for 2 seconds
deepsleep(); //Enter deepsleep mode
//-- zzZZ sleep here for 2 seconds -------------------
myled = 0; //Switch LED on after wakeup
wait(1); //Run state for 1 sec
}
}
Megjegyzés: A fenti programban
a deepsleep()
függvényhívással a mikrovezérlőt "mélyalvás" energiatakarékos módba
állítjuk, s itt a programfutás megáll. "Felébredés" (wakeup) után a
program a deepsleep()
függvényhívást követő első utasítással folytatódik.