Lekce 32 - Arduino a časování procesů v programu
29.07.2014 19:47Translate to English
Tento tutoriál trošku navazuje na lekci 29 s tím, že se více zaměřuje na časování procesů.
V dnešní lekci se zaměříme trochu na teorii a řekneme si něco o tom jak načasovat jednotlivé procesy v programu tak, abychom nemuseli vůbec pracovat s funkcí delay(). Už se Vám určitě při programování stalo, že potřebujete zajistit, aby procesy které se opakují a společně nemají stejnou časovou základnu napsat naprogramovat nějak elegantně bez psaní složitého kódu. Já použiji příklad, který svou jednoduchostí jde napsat i pomocí funkce delay(), ale pro pochopení principu se bude hodit.
Mějme napsat program který bude blikat 3 LED diodami, ale každou v jiném intervalu. Interval pro první LED bude 1 vteřina, pro druhou 3 vteřiny a pro třetí to bude 5 vteřin. S použitím funkce delay() by to vypadalo takto:
Já jsem tento masakr ani nedopsal, neboť abych dosáhl možnost opakování cyklu v loop(), musel bych zpracovat ještě 15 vteřin. Řešení není složité. Využijeme funkci millis(), která vrací počet milisekund od zapnutí nebo restartování Arduina a podle toto spočítáme, jestli se má část programu ve smyčce loop vykonat. Program si vlastně rozdělíme na několik částí, které se budou vykonávat v různých časových intervalech. Vypadá to takto:
Když odmažete komentáře, zjistíte, že kód není složitý. Důležité je pochopit jak program funguje. Při startu programu, po načtení knihoven, deklarování proměnných Ardunino projede celou funkci setup(), kde zadáváme nastavení. (např. nastavíme sériový port, inicializujeme LCD displej apod.) Tuto část Arduino po startu systému projede jen jednou. Funkce loop() naopak, když dojde na konec tak se opět vrátí na začátek a pořád tuto funkci projíždí v cyklech do nekonečna.
Když si tedy trošku rozebereme části v posledním napsaném kódu tak zjistíme, že jsme nejdříve deklarovali 3 proměnné a to
-
long lastJob1, lastJob2 = 0, lastJob3 = 0;
- tyto proměnné budeme využívat pro uchování času, kdy byla určitá část programu vykonána. Proč jsou 3? Protože máme 3 různé časové intervaly, ve kterých se bude něco vykonávat. V našem případě rozsvícení a zhasnutí LED diody. Proč je proměnná deklarována jako long? Protože budeme využívat funkci millis(), která vrací počet milisekund od startu Arduina a vrací právě 32 bitové číslo. Tedy integer (int) jelikož je pouze 16 bitové číslo tak by to při běhu programu nad 25 dní nestačilo. Prostě je to long. Co se stane, když počet milisekund bude tak velký, že se nevejde ani do čísla formátu long? Na to je Arduino připraveno a nastane to přibližně za 50 dní běhu programu. Proměnná tzv. přeteče a bude počítat opět od 0.
-
int LED1 = 9;
-
int LED2 = 10;
-
int LED3 = 11;
- nemusíme moc komentovat. Aby jsme nemuseli psát do funkce digitalWrite čísla pinů, na kterých máme připojeny LED diody, uložíme si čísla pinů do proměnných a místo čísel píšeme do kódu jen název proměnné. Je to výhodné taky z důvodu, že když změníme piny, na kterých máme LED diody, přepíšeme pouze tyto řádky. Delší možnost jak to udělat je pomocí klíčového slova #define. Pozor, potom ovšem už středník na konci není, nejedná se totiž o příkaz.
-
#define LED1 9
Jako další máme funkci setup() ve které se neudělá nic jiného, než, že se nastaví piny s LED diodami jako výstupní a všechny po startu budou hned rozsvícené. Zajímat nás bude pouze funkce loop() ve které hned narazíme na první podmínku:
-
if (millis() > (1000 + lastJob1))
Tato vyhodnocuje zdali se má tato část programu uvedená ve složených závorkách vykonat. Tak si to nasimulujeme. Hned po startu Arduina bude počet milisekund, který vrátí funkce millis() teoreticky 0. V proměnné lastJob1 máme také zatím uloženou 0. Příklad tedy zní 0 > 1000 + 0 - podmínka nění splněná a Arduino tento blok programu přeskočí. A jde dál. Dojde na konec funkce loop() a vrátí se na začátek jmenované funkce. A podmínku vyhodnotí znovu. Ale tato opět není splněna (já jsem si to změřil a Arduino funkci loop() v našem programu prošlo za 1,163 ms) a celé se to opakuje až najednou počet milisekund od startu je 1001 a podmínka pro vykonání našeho bloku je splněna. 1001 > 1000 + 0. Vykoná se toto:
-
if (digitalRead(LED1) == 0) digitalWrite(LED1, HIGH);
-
else digitalWrite(LED1, LOW);
-
lastJob1 = millis();
První dva řádky říkáme Arduinu, že když je LED dioda zhaslá tak jí rozsviť a když ne tak jí zhasni. Program tedy vykonal naši práci v určitém intervalu, kterou jsme chtěli. Důležité je uložit čas, kdy se tak stalo. V našem případě to je zhruba 1001ms, kterou program uloží do proměnné lastJob1. A jede se dál. A vyhodnocování dalších bloků programu nepíši, jsou analogií tohoto bloku, pouze s jiným intervalem. Program tedy dál běhá v cyklu loop() až a čase 2002ms doběhne k naší podmínce, kde vyhodnotí že 2002 > (1000 + 1001) a diodu opět zhasne, protože poslední čas provedení bloku programu byl uložen jako 1001ms v proměnné lastJob1.
Takto Arduino vyhodnocuje všechny 3 naše bloky a různých intervalech rozsvěcí a zhasíná LED diody. Samozřejmě bude spíše vykonávat jiné činnosti např. interval zobrazení nějaké hodnoty na displeji bude rozdílný od intervalu ukládání této hodnoty např. na SD kartu. Možnosti využití jsou zcela na Vás. Nezapomeňte, že za tyto bloky programu můžete napsat kód který nebude ovlivněn časem a vykoná se vždy, kdy Arduino ve smyčce loop() k němu dojde. Můžete i bloky programu s časovou podmínkou přidávat a mít jich teoreticky velmi mnoho.
———
ZpětDiskusní téma: Lekce 32 - Arduino a časování procesů v programu
Datum | 06.05.2015 |
---|---|
Vložil | look |
Titulek | Re: Re: Re: Re: Re: Re: Funkce millis() a datový typ |
I to není řešení pokud millis() přeteče a začne od nuly, poslední proces bude mít uložený čas před přetečením, tak se IF nevyhodnotí.
———
Datum | 08.05.2015 |
---|---|
Vložil | look |
Titulek | Re: Re: Re: Re: Re: Re: Re: Funkce millis() a datový typ |
Pardon, beru zpět svůj předchozí příspěvek.
Zkoušel jsem a je to ok.
Správně jsou obě verze.
if((unsigned long)(millis() - lastJob) >= interval)
if(millis() >= (unsigned long)(lastJob + interval))
———
Datum | 29.05.2015 |
---|---|
Vložil | GuzA |
Titulek | Re: Re: Re: Re: Re: Re: Re: Re: Funkce millis() a datový typ |
Může mi toto někdo vysvětlit blíže. Děkuji...
———
Datum | 02.10.2015 |
---|---|
Vložil | LuBoss |
Titulek | Re: Re: Re: Re: Re: Re: Re: Re: Re: Funkce millis() a datový typ |
Typ long přeteče po hodnotě 2 147 483 647 na hodnotu -2 147 483 648, kdežto unsigned long přeteče po hodnotě 4 294 967 295 na 0. Pokud se tedy u maximální hodnoty typu long přičte +1, tak výsledek bude -2147483648, což je v lidském počítání neobvyklé. Ale proč prostě nepoužívat všude unsigned proměnné? Nevýhoda unsigned proměnných je jediná, ale zásadní - neumí záporná čísla (nemají pozici pro znaménko). Je ale spousta situací, kdy je potřeba pracovat i se zápornými hodnotami a proto jsou výsledky různých funkcí a výpočtů defaultně jako signed typ, tedy se znaménkem, ale polovičním rozsahem kladné max. hodnoty.
———
Datum | 27.03.2021 |
---|---|
Vložil | Kamil |
Titulek | Re: Re: Re: Re: Re: Re: Funkce millis() a datový typ |
Je zajimave, ze nikdo nevi, jaky format funkce millis poskytuje? :) Za mne, pokud pouzijeme stejny format, jako vraci funkce millis, pretece nam jak soucet, tak casovac, tzn vsechny casove useky budou stejne i pri preteceni. Mame-li pri 8 bitech hodnotu 250 a pricteme-li 10, dostaneme 5..