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. Schéma obvodu Jde zejména o schéma zapojení sedmisegmentového displeje s řadičem MAX7219, který je schopný ovládat i displej o dvojnásobném počtu číslic, než my použijeme. "Náš" displej je čtyřmístný se společnou katodou (jde o tentýž displej, jaký najdeme na desce Tinylabu) a je připojen přímo na driver MAX7219. Tento driver se k Arduinu připojí piny DIN, CLK a Load, což je vyznačeno ve schématu. Kromě displeje je ve schématu vyznačeno i zapojení dvou ovládacích tlačítek, které je velmi jednoduché.

Program

Potom co zapojíme obvod (pokud nemáme desku Tinylab), tak naprogramujeme Arduino na desce Tinylab nebo samotné. Zapojíme kabel do USB portu Arduina a druhým koncem do počítače. Potom správně nastavíme port v Arduino IDE a vložíme nebo vepíšeme následující kód:
#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: millis už známe, startMS obsahuje hodnotu funkce millis při spuštění a pausedMS obsahuje dobu pozastavení stopek od resetu. Začněme výpočtem času od spuštění takto:
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.

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

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.

Komentáře


login key | help
Používáním tohoto webu souhlasíste se shromažďováním údajů o vás. Více informací