Arduino stopky (založené na funkci millis)
Úvod
Ve většině oblastí programování jsou nějaké typické programy, které se postupně vytvářejí, když začínáte. Podle mého názoru mezi tyto programy patří blikání LED, kalkulačka nebo stopky. A právě na ty stopky se dnes podíváme.Zapojení
Na prakticky jakýkoliv projekt s Arduinem potřebujeme nějaký obvod. Stopky nejsou výjimkou, a proto budeme i teď něco zapojovat. Nebo ne? Záleží na tom, zda máte (a chcete použít) svou desku Tinylab. Program je napsaný přímo pro ni, tedy stačí nahrát a připojit na elektřinu. Pokud desku Tinylab nemáte, tak můžete využít schéma zapojení vpravo, podle kterého zapojíte obvod ekvivalentní využitým součástkám Tinylabu.
Program
Potom co zapojíme obvod (pokud nemáme desku Tinylab), tak naprogramujeme Arduino na desce Tinylab nebo samotné. Zapojíme kabel do
#include <LedControl.h> //Do programu přidáme knihovnu pro obsluhu 7-segmentového displeje
LedControl lc(10, 12, 11, 1); //Inicializujeme objekt 7-segmentového displeje
//Deklarujeme různé proměnné
uint32_t startMS = 0; //Milisekundy při startu
uint32_t stopMS = 0; //Milisekundy při pozastavení
uint32_t pausedMS = 0; //Celková doba pozastavení
uint32_t bufferMS = 0; //Při pauze nebo zastavení budeme vypisovat hodnotu této proměnné
bool started = false; //Jsou stopky spuštěny?
bool paused = false; //Jsou stopky pozastaveny?
void setup() {
lc.shutdown(0, false); //Nastavíme vypnutí displeje na nepravda - čili zapneme displej
//Číslo na začátku parametrů každé funkce značí index displeje.
//Knihovna totiž podporuje několik zřetězených driverů, z nichž každý ovládá jeden displej
lc.clearDisplay(0); //Smažeme displej
lc.setIntensity(0,6); //Nastavíme jas displeje (hodnoty jsou 0-15)
pinMode(8,INPUT_PULLUP);//Nastavíme pin 8 s tlačítkem jako vstupní s pullup rezistorem
pinMode(9,INPUT_PULLUP);//Totéž provedeme s pinem 9 (na němž je též tlačítko)
}
byte digitOnPosition(int num, byte pos) {
for(byte i = 0; i < pos; i++) {
num /= 10;
}
return num % 10;
}
void printNumber(float i){//Tato funkce vypíše na displej číslo
for(int j = 0; j < 4; j++) {
byte digit = digitOnPosition(i*100, j); //Funkce digitOnPosition vrací číslici
//čísla i*100 na pozici j
lc.setDigit(0, 3 - j, digit, j == 2); //Na displeji zobrazíme číslici digit
// na pozici 3-j a pokud se j = 2 (to je to j == 2) tak zobrazíme desetinnou tečku
}
}
void loop() {
if(!digitalRead(8)){//Při zapojení pullup rezistoru je logika opačná
if(!started){// Nejsou stopky spuštěny?
startMS = millis();//Milisekundy při startu nastavíme na současnou hodnotu počitadla
started = true;//Proměnnou zapnuto nastavíme na pravda
}
else if(!paused){//Stopky nejsou pozastaveny?
//kód je v podstatě stejný jako dříve, proto ho nebudu popisovat
stopMS = millis();
paused = true;
bufferMS = millis() - startMS; //Do proměnné bufferMS uložíme čas od spuštění
bufferMS -= pausedMS; // Od času od spuštění odečteme čas strávený v pauze
}
else if(paused){
paused = false;//Proměnnou pozastaveno nastavíme na nepravda
pausedMS += millis()-stopMS; //K milisekundám ztraceným při pauze přičteme další dobu
}
while(!digitalRead(8));//počkáme, dokud není tlačítko uvolněno
delay(80); // Počkáme 80ms pro ošetření zákmitů
}
if(!digitalRead(9)){
pausedMS = 0;//Vše vynulujeme
started = false;
paused = false;
while(!digitalRead(9));//počkáme, dokud není tlačítko uvolněno
delay(80); // Počkáme 80ms pro ošetření zákmitů
}
uint32_t time = millis() - startMS; //Do proměnné time uložíme čas od spuštění
time -= pausedMS; // Od času od spuštění odečteme čas strávený v pauze
if(paused)time = bufferMS; //Pokud jsou stopky pozastaveny, vypisujeme bufferMS
else if(!started) time = 0; //Pokud jsou stopky zastaveny, vypisujeme nulu
printNumber(time / 1000.0);
}
Po nahrání programu do Arduina si popíšeme, jak kód funguje.
Popis kódu
Začněme v kódu hodně využívanou funkcí millis. Název millis je zkratkou od milliseconds, což jsou - jak název napovídá - milisekundy. Tato funkce vrací počet milisekund od začátku běhu programu.Na začátku programu vložíme knihovnu LedControl, kteá slouží k ovládání sedmisegmentového displeje. V konstruktoru poté do ní vložíme počet řadičů za sebou a piny. Potom definujeme proměnné pro ukládání stavu funkce millis() v určitých dobách (např. start nebo pauza) a také proměnné, v nichž je stav stopek (tedy pozastavení nebo nastartováno) a nakonec je tam proměnná bufferMS, která slouží k uložení stavu stopek při pauze, tedy hodnota této proměnné se vypisuje na displej při pozastavení. Dále je funkce setup, kterou není třeba popisovat, jelikož jde o jednoduché funkce, které jsou popsány v komentářích. Po funkci setup následuje funkce loop, v níž hned na začátku kontolujeme, jsetli je stisknuto tlačítko 2, připojené na pin 8, které spouští a pozastavuje stopky. Pokud je stisknuto, tak se spouští vnořená podmínka, v níž kontolujeme, zda jsou stopky spuštěny, a pokud nejsou, tak je spustíme tak, že nastavíme proměnnou started na true, tedy pravda, a proměnnou startMS na hodnotu z funkce millis. Tuto hodnotu totiž budeme od funkce millis odečítat při výpočtu naměřeného času. V podmínce, v níž jsme kontrolovali spuštění stopek, pokračujeme při jejím nesplnění na další větev (to je to else if, které vysvětlím níže), ve které kontrolujeme, jestli jsou stopky pozastaveny, a pokud ne (to je ten vykřičník, který označuje negaci) tak je pozastavíme. To se udělá nastavením proměnné stopMS na hodnotu proměnné millis (jelikož z ní potom vypočteme dobu pauzy) a nastavením proměnné paused na true. Potom pomocí níže popsaného způsobu uložíme do proměnné bufferMS změřený čas ve chvíli, kdy byly stopky pozastaveny. Za předpokladu, že ani tato podmínka není splněna, tak pokračujeme ke třetí větvi programu, kde je to else if jen tak pro přehlednost, čili bez něj bude program fungovat dobře. V této větvi podmínky znovu spouštíme stopky po pozastavení (anglický výraz pro toto "znovuspuštění" je resume). Jde o jednoduchý proces, při němž se hodnota proměnné paused nastaví na false a do proměnné pausedMS se přičte doba pauzy. Jen na závěr této podmínky uveďme, že se čeká na uvolnění tlačítka, ale stopky začínají měřit už od doby jeho stisku.
Za předpokladu, že tlačítko 2 nebylo stisknuto, se kontoluje, jestli nebylo stisknuto tlačítko 1. Pokud ano, tak se stopky vynulují a hodnota většiny proměnných se nastaví na 0 (u proměnných startMS a stopMS toto nemá smysl, jelikož jejich hodnota se aktualizuje, až to bude potřeba) a počká se na uvolnění tlačítka.
Na konci funkce loop vypisujeme na displej hodnotu proměnné time, která obsahuje buďto čas stopek, anebo hodnotu proměnné bufferMS (při zastavení je v ní 0)
Výpočet času
Tato část textu nebude až tak o programování, ale o výpočtu času, který se vypisuje na displej. Tento čas počítáme z těchto proměnných:- Hodnota funkce millis
- Proměnná startMS
- Proměnná pausedMS
long time = millis() - startMS;
Po tomto výpočtu v proměnné time máme čas od spuštění včetně celkové doby pozastavení. Ovšem pokud naměříme např. 2 s, potom
stopky pozastavíme a pak je po třech vteřinách znovu spustíme, naměříme 4 vteřiny a stopky zastavíme, tak by displej ukázal
9 vteřin, ovšem my potřebujeme, abz ukázal 6 vteřin, jelikož tři vteřiny byly stopky pozastaveny. Proto máme proměnnou pausedMS,
v níž je celková doba pozastavení. Proto od proměnné time odečteme proměnnou pausedMS. Celkový vzorec pak vypadá takto:
long time = (millis() - startMS)-pausedMS

Jak funguje else if aneb Kontrola více podmínek
Pokud jste si všimli, tak v kódu byla použita podmínka napsaná stylem if...then......else if...then. Tento zápis slouží k tomu, aby při kontrole více souvisejících věcí nedocházelo zbytečně ke kontrolám dalších podmínek, když byla jedna už splněna. Podmíkna if...else if...else má výhodu v tom, že pomocí ní lze snadno napsat řízení programu číselnou nebo řetězcovou proměnnou, načítání tlačítek v určitém pořadí nebo podobné programy. Podíváme se na to, jak bychom pomocí této podmínky napsali řízení programu řetězcem:
if(string == "vypnout"){
print("Vypinam...");
switchOff();
}
else if(string == "rozsvitit"){
print("Rozsvecuji...");
lightOn();
}
else if(string == "zhasnout"){
print("Zhasinam...");
lightOff();
}
else{
print("Neznamy prikaz!");
}
Pokud rozumíte vývojovému diagramu, tak jsem navíc nakreslil diagram podmínky else if. Je nahoře nad programem.
print("Vypinam...");
switchOff();
}
else if(string == "rozsvitit"){
print("Rozsvecuji...");
lightOn();
}
else if(string == "zhasnout"){
print("Zhasinam...");
lightOff();
}
else{
print("Neznamy prikaz!");
}
Závěr
Tento návod má za cíl vás naučit něco víc o programování Arduina. Pokud chcete, tak si můžete také vyzkoušet vyrobit projekt Arduino kalkulačka s vytisknutou krabičkou.Novinky
Nové návody pro Nextion
V budoucnosti můžete na tomto webu očekávat také návody pro displej Nextion. V současnosti pracuji na meteostanici s ukládáním dat na tomto serveru.Fórum opět spuštěno
5. prosince jsem zjistil, že roboti nepřistupují tak často, aby mohli způsobit nějaký problém s výkonem webu. Proto jsem se rozhodl fórum znovu aktivovat.Redesign tmavého režimu
Na počátku prosince jsem provedl redesign tmavého režimu. Menu je nyní tmavší, stejně jako pozadí stránky. Pozadí textu je také tmavší. Rozložení prvků je stejné, jako dříve.Podezření na DDoS
Asi osmého listopadu 2022 jsem zaznamanal prudký vzestup návštěvnosti. V logu jsem zjistil, že jde pravděpodobně o robota, který přistupuje na fórum. Proto jsem fórum dočasně deaktivoval.Změna administrace
16. září přibylo nové menu, nastavení pravého sloupce v administraci, tmavý režim vázaný, na uživatele, nový vzhled administrace a ještě pár drobností. Většina tohoto je dostupná jen pro registrované uživatele.Soukromé zprávy (PM)
Na tomto webu 9. září přibyly soukromé zprávy. Využívat je mohou registrovaní uživatelé. Adresát se určuje zadáním uživatelského jména a v adresním políčku funguje našeptávač. Ovšem ten, který nepíše na fórum, není v našeptávači vidět.Nové fórum zde
24.srpna 2022 jsem na tomto webu spustil fórum. Je dostupné v menu vedle článků a jde kompletně o můj vlastní program.Blikání LED různě
22.srpna 2022 jsem zveřejnil různé způsoby blikání LED. Tento projekt je často označován za "druhý projekt", hned po blikání LED normálním způsobem.Stopky s Arduinem
18.srpna 2022 jsem vydal článek o stopkách. Jde o jeden z článků o "začátečnických projektech", které mají za cíl naučit vás více o programování Arduina v praxi.Arduino kalkukačka
6. dubna tohoto roku jsem naprogramoval kalkulačku řízenou Arduinem Uno. V tomto článku jsem popsal její funkce a konstrukci.USB konektory
Před nedávnou dobou vyšel článek o USB konektorech, jejich využití a funkci. Popisuje všechny dostupné běžné konektory i místo, kde je najdeme.Tinylab budík
Nedávno jsem vydal článek o budíku řízeném Arduinem, co je založený na desce Tinylab. Tento článek popisuje všechny funkce budíku i desku Tinylab.© Tatatiti, Jan Cviček, 2022
Komentáře
Nový komentář