Arduino – Časování pomocí intervalů

IMG_8754_webPokud to považuji za vhodné, tak v některých projektech používám platformu Arduino. Koncepce programové konstrukce aplikace pro Arduino spočívá ve dvou hlavních metodách – setup() a loop(), ve které program neustále běží. Pro pohodlnější práci s obsluhou periodických procesů jsem napsal jednoduchou knihovnu, která tyto úkoly umožňuje napsat velmi elegantním způsobem.Knihovna interval vytváří časovací objekty a zpřístupňuje dvě metody – metodu set a metodu expired. Metoda set se používá k nastavení timeoutu a definici začátku časování, metoda expired pak slouží k ověření, zda nastavený interval již vypršel. Zajímavostí je, že knihovna korektně ošetřuje přetečení vnitřního milisekundového čítače, takže nehrozí nebezpečí špatného časování i při velmi dlouhé době chodu zařízení.

Příklad použití – modifikované demo BlinkWithoutDelay.ino

40 thoughts on “Arduino – Časování pomocí intervalů”

  1. Celkem dobrý, je nutný aby se ta funkce jmenovala blink, nebo to bude fungovat i s jinými názvy pro více úrovní časování?

    1. Blink je jen symbolické pojmenování vytvořené instance. Pojmenovat ji je možné jakkoliv – dle konvencí C++, a těchto instancí může být také více. Omezení je pouze dostupná RAM…

      1. Ahoj, vyzkoušel jsem se dvěma instancemi, jedna 1000 a druhá 2000 milis, vždy po expiraci se vypíše která instance expirovala, ale vypisuje se následovně:
        Expirace1
        Expirace2
        Expirace1
        Expirace1
        Expirace2

        Tedy, po druhé expiraci první instance, se nevypíše expirace té druhé, pak to zase funguje a tak stále dokola, nějaká rada?

        1. Ahoj. To, co vidím je ale správně ne? První výpis je (předpokládám) začátek, kdy oba intervaly expirovaly. Následně 2x expiruje ten, co je nastavený na 1 sekundu a hned za ním ten, co je nastavený na 2 sekundy…

  2. odzkoušeno, celkem zjednodušení programu při časování různých událostí (čtení senzorů, výpis na displej, na web…)
    dobrá práce.

  3. Dobrý den, chtěl bych požádat o obecnou radu. Z Vašeho blogu je jasné, že s Arduinem „dost kamarádíte“. Já s ním začínám a upřímně řečeno, jejich IDE mi příliš nevyhovuje. Zvykl jsem si u pokročilejších nástrojů na různé nápovědy a automatické doplňování přímo při psaní kódu. Našel jsem si Code Blocks, kde mi základní věci chodí, ale některé dodatečně instalované knihovny jsem nerozchodil. Prosím, jaké IDE používáte Vy? Co by jste doporučil? A ještě jedna prosba. Pokud je kód delší, jak ho lze jednoduše rozdělit do více souborů? Například: deklarace v jednom souboru, funkce v druhém a vlastní program ve třetím. Děkuji za radu. David

    1. Dobrý den, jako IDE pro Arduino projekty jsem vyzkoušel Maria Mole, ArduinoCodeBlocks, Arduino Sublime a IDE4Arduino – originální „IDE“ mi také nevyhovuje, jenomže jsem nakonec u něj stejně skončil. Co se týče pořadí, jak moc jsem jednotlivé nástroje používal, tak je to asi takhle:
      ArduinoCodeBlocks – rychlé, funkční, knihovny mohly být součástí projektu, takže se nic nemuselo doinstalovávat do IDE a dalo se vše poslat v jednom ZIPu – používal jsem asi nejvíce.
      Maria Mole – relativně nový projekt, který ale ustrnul (nevím jak teď) a neměl spoustu věcí, co CodeBlocks ano.
      Arduino Sublime – velmi nadějně vypadající, chystal jsem se ho začít používat jenže nastaly důvody, které proberu na závěr.
      Ostatní jmenované jsem ani moc podrobně nezkoušel, protože – a teď přijdou ty důvody – nastoupilo Arduino pro ESP8266 moduly. Jediná reálná funkční konfigurace, o které vím, je standardní IDE (používám verzi 1.6.5 v konfiguraci „Portable“) s pluginem pro překlad pro ESP8266, takže jsem byl dotlačený do originálního „IDE“. Ve skutečnosti texty edituji v Notepad++.
      Co se týče dělení, tak se snažím o klasické dělení – deklarace (a dokumentace) v .h souboru, výkonné funkce v .cpp a hlavní program stejně musí být v .ino. Pokud je to větší projekt a jen trošku to jde, tak v .ino mám jen setup() a loop(), ve kterých jsou použity objekty z jiných souborů.
      Pavel

    1. Dobrý večer. Každá z těch knihoven byla vytvořená pro jiný účel – můj interval slouží jako jednoduchá eliminace delay() v kódu a tím „znehybnění“ zbytku aplikace, zatímco tasker umožňuje zdánlivě paralelní spuštění více vláken. Interval bude mít jednodušší použití, zatímco tasker nabízí více možností, jak celý program postavit a rozdělit na jednotlivá vlákna. Co zase tasker neumí a můj interval v poslední (zatím neuveřejněné verzi) ano, je zjištění kolik ze zadaného intervalu zbývá času a kolik času již uběhlo od začátku časování.

      1. Po delší době zkouším zkompilovat progámky s toto funkcí na novém pc, IDE1.6.10, knihovnu interval mám nainstalovanou, a při kompilaci hlásí tuhle chybu: /home/karel/Arduino/libraries/interval/interval.cpp:6:21: fatal error: arduino.h: No such file or directory
        #include
        co s tím?

        1. Podle cesty k souboru jde o překlad pod linuxem – je třeba arduino.h nahradit Arduino.h – Linux je totiž citlivý na velikost písmen a já v tomto měl chybu, protože jsem původně pracoval jen pod Windows.

  4. Dobrý den
    Vím že můj příspěvek nesouvisí přímo s tímto článkem ale nevím na koho se obrátit. Chci vytvořit bargraph, s buzením pře I2C. Zkusil jsem využít tuto knihovnu http://playground.arduino.cc/Code/LcdBarGraph ale vůbec se mi ji nedaří zprovoznit ani příklady v ní. Prosím mohl by jste mi pomoci se setsavením knihoven tak, aby aby i tato zmíněná knihovna fungovala nebo lze bargraph přes I2C vytvořit i jinak? Díky za jakoukoliv odpověd.

  5. Dobrý den,
    s arduinem se teprve učím a tak vás prosím jestli by jste mi mohl vysvětlit jak se vaše knihovna používá nějak to nemůžu pochopit.Potřeboval bych udělat zvukovou signalizaci na rozvícení světla s prodlevou pokud tam dám delay tak po zhasnutí zařízení píská dokud neuběhne daná prodleva.
    Předem děkuji za odpověd

    1. Dobrý večer,
      knihovna přímo obsahuje příklad použití, ale pokud nedostačuje, tak to můžeme rozebrat. Takže přesně potřebujete co? Nebojte se rozepsat podrobněji co máte hotové, co je kam připojené a jak si představujete výsledek…

  6. takže kod:
    #include
    #include „interval.h“
    int hodnota = 1;
    Interval blink;

    void setup() {
    Serial.begin(9600);
    pinMode(2,INPUT);
    pinMode(5,INPUT);
    pinMode(4,OUTPUT);

    }

    void loop() {
    Serial.println(set()/2);
    int stav = digitalRead (5);
    if(stav == 0){
    if (blink.expired()) {
    blink.set(set()*30000);
    tone(4, 392);}}
    if(stav == 1){noTone (4);}

    }

    float set(){

    int tl1;
    tl1 = digitalRead(2);
    hodnota = EEPROM.read(0);
    if(tl1 == 0){ hodnota = hodnota + 1; }
    if(hodnota > 10){ hodnota = 1; }
    EEPROM.update(0, hodnota);
    delay(100);
    return hodnota;

    }

    na pin 2 je připojene tlačítko kterým se nastabje prodleva
    na pin 3 repruduktor
    a na pin 5 světelné čidlo

    jde o zařízení do lednice která má udělat zvukovou signalizaci když někdo nechá otevřené dveře ale musí se nastavit prodleva aby zařízení nepípalo při každém otevření ledničky

    1. Jistě – nefunguje to proto, protože časovač (interval) běží stále. Zkuste udělat to, že za příkaz noTone(4); dáte blink.set(set() * 30000); a nastavení časovače před tone(4, 392) odstraníte. Pak celý skript bude pracovat tak, že se neustále nastavuje časovač na potřebnou dobu a ve chvíli otevření dveří se teprve začne hlídat a testovat, jestli nevypršel.
      Další věcí je, že používáte všude int a neuvedl jste typ používaného Arduina. Pokud to je některé s procesorem AVR 8 bitů (Leonardo, Nano, Micro, Mega, …), tak je int definován v rozmezí -32767 až +32768, což může zmást kompilátor při násobení * 30000. Navíc proměnnou hodnota máte nadeklarovanou jako int a přitom set() má výstup float. Doporučuji tedy další následující úpravy:
      1. uint32_t hodnota = 1;
      2.
      uint32_t set()
      {
      hodnota = EEPROM.read(0);
      if (0 == digitalRead(2))
      ++hodnota;
      if (10 < hodnota) hodnota = 1; EEPROM.update(0, (uint8_t)hodnota); return hodnota; } Důvody, proč jsem udělal tyto změny konstrukce: 1. rozsah proměnné hodnota koresponduje s vstupním rozsahem objektu blink 2. zápis porovnání (0 == digital.....), který vypadá "obrácený" je záměr - pokud opomenete vynechat jedno rovnátko ve Vašem zápisu, tak to kompilátor nezahlásí, protože výraz tl1 = 0 je platnou konstrukcí jazyka C/C++ a budete honit chybu, která nebude zřetelná, zatímco v mém zápisu pokud zapomenete napsat dvě rovnítka vyhlásí překladač chybu 3. přetypování (uint8_t) je opět z toho důvodu, že Arduino maskuje varování překladače, takže se nedozvíte, jakou konverzi použil, protože parametr EEPROM.update v položce dat je jeden byte (uint8_t) Vyzkoušejte a dejte vědět výsledek...

  7. Dobrý den,
    Chtěl jsem se zeptat jestli neumíte sestavit program pro arduino uno. Použití fotorezistoru s odporem 10k se zapojením A0 a výstupem na který koli pin se zapojeným mosfetem. Použití soumrakový spínač na led pásek, ale od setmění dojde k sepnutí a s možností nastavení času v programu jak dlouho má byt sepnutý obvod po setmění. Přiklad: Setmi se Ardurino sepne obvod s časem nastavením 3hod jak se rozední obvod vypne nebo bude vypnut podle daného času a tak dokola. Jsem laik ,ale něco maličko umím našel jsem nějake programy na fotorezitor ale ten čas k tomu dát neumím a nikde sem to nenašel. Předem díky.

    1. Dobrý den,
      zkuste použít stavový automat – v prvním stavu budete testovat, zda je intenzita osvětlení pod Vámi specifikovanou úrovní, pokud ne, tak testujete stále dokola, pokud ano, tak inicializujete interval na požadovaný čas, rozsvítíte LED a přejdete na stav 2. Ve stavu 2 budete jen testovat, zda vypršel interval – pokud ne, tak testujete stále dokola, pokud ano, tak zhasnete LED a přejdete do stavu 3. Ve stavu 3 budete testovat intenzitu osvětlení a čekat, až stoupne nad Vámi specifikovanou úroveň (čekáte na rozednění), pokud je světla málo, tak stále testujete a čekáte, pokud je světla dostatek, tak přejdete do stavu 1. Algoritmus se dá doplnit o ošetření přechodů světlo< ->tma tak, aby to při přechodech neblikalo.

      1. Našel jsem tento program byl ve španělštině trochu jsem ho přegoglil a nahrál do arduina s testovací svítivou led diodou misto spinaciho tranzistoru funguje dobře , ale tady končím neumin napsat ten spínací čas.Poradíte..???. s těmi přikazy sem mimo. Děkuji.

        //nastavte proměnné

        int luz = 0;

        int odpor = 0;

        int limit = 50;

        //vytvořit porty (pin)

        void setup()

        {

        Serial.begin(9600);

        pinMode(6, OUTPUT);

        pinMode(A0, INPUT);

        }

        void loop()

        {

        //přijímat informace od fotorezisty

        odpor = analogRead(A0);

        luz = (5.0 * odpor * 100.0) / 1024.0;

        //tisknout hodnoty

        Serial.print(luz);

        Serial.println(“ LUZ“);

        Serial.print(odpor);

        Serial.println(“ Ohms“);

        delay(300);

        //podmínky pro zapnutí světla

        if (luz limit) {

        digitalWrite(6, 0);

        }

        }

        1. Dobrý den,
          myslím, že jsem poradil, ale vypadá to, že spíš chcete, aby to někdo napsal za Vás… 🙁 Zkuste si něco nastduovat a moje rady aspoň nějak zapracovat do kódu. Mimochodem WordPress zkresluje příspěvky, protože to není fórum, takže možná bude lepší zvolit komunikaci mailem.

  8. Ahoj.
    Prosimtě chci se zeptat…. Nevim jak z toho ven….
    Používam interval od tebe. Chci ho použít v programu jako tzv. Delay On a taky jako Delay Off. Takže pri pruběhu programu dokola, potřebuju nastavit ten čas pouze jednou a až potom změnit vystup. Jenže jak ten program jede dokola, tak nevim jakou podminku dat k tomu přikazu set.
    Je nějaké snadné řešení jak z toho ven?? Aby to udělalo vždy jen jednou v programu? Díky za rady 🙂

    Tuším, psal jsi že maš nejakou nezveřejněnou verzi ktera ukazuje i kolik času zbyva…..nedalo by se to využít zrovna pro moji potřebu?

    1. Ahoj,
      chapu to tak, ze cas chces zadavat jen jednou? Pokud ano, tak uprav objekt intreval tak, aby .set uschoval do pomocne promenne tu hodnotu a dopln metodu treba .reload, ktera pouzije uschovanou hodnotu ze .set

  9. ahoj,
    neslo by upravit tvou knihovnu tak, aby nemuseli byt pouzivany funkce .expired a .set? Prijde mi to zbytecne prodlouzeni kodu. Pokud funkci volam, tak bud rovnou s parametrem = nastavi cas, nebo bez parametru = vrati true/false podle stavu.

    Nebo to ma nejaky duvod, ktery nevidim?

    1. Ahoj,
      vždycky jsem si myslel, že jménem se volá pouze konstruktor objektu, pro volání vnitřních metod je tečková konvence, takže nevím, jak to udělat jinak. Jedině snad sloučit .expired a .set do jedné metody, ale ta se bude muset volat tečkovaně také…

      1. jo, vcera zkousel neco vymyslet a nakonec jsem to vzdal. Tak jsem aspon zkratil „.expired“ na „.exp“ 🙂

        jeste jsem uvazoval o tom pridat funkci, ktera by pri kazde expiraci prepnula mezi true/false. Usetrilo by to dost kodu pri konstrukci ruznych blikacu a tak. Misto deklarovani bool promenne a jejiho prenastavovani by stacilo zeptat na stav.

        1. 🙂 . To s tím přepínáním není špatný nápad – kdyby se to spojilo s autoreload automatikou a ukládáním původní hodnoty, jak už v diskuzi také zaznělo. Možná je už fakt čas, abych aspoň Interval hodil na github – tam by se ta knihovna asi spravovala nejsnadněji.

          1. takze Interval
            .set(xxx) – nastavi cas na xxx ms
            .reset – znovu spusti s naposled nastavenym casem
            .exp – overi expiraci
            .out – overi sudy/lichy interval
            .left – zbyvajici cas v ms do expirace

            //to .out se mi uplne nelibi, ale nic lepsiho me nenapada 🙂

      1. hmm, mas recht. Skoda ze ArduinoIDE neumi provadet nejake pokrocilejsi „najit&nahradit“, pokud by zjistilo ze ma novejsi knihovnu nez byla pouzita v projektu 🙂
        —————–
        K tomu doplneni knihovny o dlasi funkce se taky dostanes?

  10. Takže původní funkčnost je zachována a jsou tam další „feature“? to asi zkusím využít, mám tuhle knihovnu v mnoha projektech. Pro nás méně chápavý by byly fajn i další příklady na ty rozšířený funkce…

    1. Release verze v0.0.1 je původní, uveřejněná zde. Master už má doplněnou funkčnost .restart, jak prošlo tady diskuzí. Další věci (toggle) doplním, ale bylo by dobrý, kdyby se Míra ozval, ať to nějak koordinujeme. Příklady budu muset teprve vyrobit.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *