[Projekt] INTERVAL Ersatzstoff


hier möchte ich euch meinen interval ersatzstoff vorstellen.

wer gar nicht weiß, worum es sich dreht, sollte dieses lesen:
blink without delay
der wachmann

hält man sich die dort vorgeschlagenen wege, auch gut und richtig ist, dann wird der quellcode mit solchen statements geflutet:
code: [select]

if(millis() - gemerktezeit >= wunschlaufzeit)
{
  // tuwas
  gemerktezeit = millis();
}

die wurst ist total korrekt.
aber dennoch unangenehm, da mit viel schreibarbeit verbunden.
es schleichen sich schnell copy+paste fehler ein.
der quellcode des projektes wird recht unübersichtlich. um schlimmer, je öfter das konstrukt darin vorkommt.


hier die von mir erstellten abstraktionen des problems:
multitasking macros
intervall macro

an dieser stelle ein herzliches danke, die spender der (in den threads versteckten) anregungen.
im folgenden habe ich versucht sie weitestgehend aufzunehmen.



zum "warum?" bei mir ein ersatzstoff, für interval und die taskmakros, muss:

eigentlich funktionieren diese dinge prächtig!
sind aber gewissen einschränkungen unterworfen, hauptsächlich der verwendung der statischen daten liegt. diese verhindern eine mehrfachverwendung der erstellten funktionen. ich nenne solche funktionen "wegwerf funktionen". denn sie sind nur einmal pro projekt nutzbar. braucht man z.b. drei unabhängige wechselblinker, dann muss man die funktion kopieren, dass man, im schlimmsten fall, 3 vollständig identische kopien in einem programm hat.
ebenso verhält es sich wenn man diese makros in klassen einbaut, dann ist nur eine instanz nutzbar. mehrere instanzen führen zu fehlverhalten. eine "wegwerf klasse".

was im prozeduralen umfeld gerade noch erträglich erscheint, macht im oop umfeld die wichtigsten oo möglichkeiten kaputt.
dabei ist doch gerade die wiederverwendbarkeit eins der vordringlichsten ziele der oop.

ist klar geworden, wo der hase im pfeffer liegt?




hier jetzt der neue ansatz, um das blinkwithoutdelay problem zu erschlagen:
blinkwithsimpletimer.ino
code: [select]
#include "combietimer.h"

combie::simpletimer timer; // timer instanz anlegen

void setup()
{
  pinmode(led_builtin,output);
    // timer.start();
}

void loop()
{
  if(timer(1000)) // wenn abgelaufen
  {
    digitalwrite(led_builtin,!digitalread(led_builtin));
    timer.start();
  }


ich nutze namespaces, da es schon eine simpletimer lib gibt, und ich damit nicht kollidieren möchte. wenn man sich den code anschaut, dann ist mein simpletimer deutlich simpler, als der fremde simpletimer.

daraus leite ich, für mich, das moralische recht ab meinen simpletimer auch zu nennen.
:smiley-twist:  :smiley-twist:


erklärung:
der simpletimer startet immer im abgelaufenen zustand. er wird bei der ersten nutzung true liefen. man das nicht, sollte man in setup() ein timer.start() notieren, wie es im beispiel vorbereitet ist.



vergleichbares hier nochmal in einer abgewandelten version:
blinkwithpulsator.ino
code: [select]

#include "combietimer.h"

combie::pulsator puls(1000); // liefert alle 1000 ms einmal true sonst false

void setup()
{
  pinmode(led_builtin,output);
  puls.start(); // dank des start(), beginnt puls mit pause
}

void loop()
{
  if(puls) digitalwrite(led_builtin,!digitalread(led_builtin));



eine entprelleinrichtung, basierend auf dem simpletimer:
tasterentprellen.ino
code: [select]
#include "combietimer.h"
using combie::entprelltimer;

const byte taster =  2; // taster gegen gnd schaltend

entprelltimer entprellen(200);   // in der praxis wird man wohl eher 20ms verwenden

void setup()
{
 pinmode(led_builtin,output);   
 pinmode(taster,input_pullup);
}

void loop()
{
  // die led zeigt das, vom prellen bereinigte, signal
  digitalwrite(led_builtin,entprellen(!digitalread(taster)));  // invers, wg. pullup
}



und zum abschluss noch eine aufgabe um ein signal zu formen:
schaltsequenz.ino
code: [select]
/**
 *    ablaufdiagramm - zeitdiagramm
 *   
 *        s1    _----------_____  schalterstellung
 *        out1  _-------------__  verzoegertes abschalten
 *        out2  ____-------_____  verzoegertes einschalten
 *
*/

#include "combietimer.h"
using namespace combie;

const byte s1   = 2; // schalter pin
const byte out1 = 3; // ausgang
const byte out2 = 4; // ausgang

entprelltimer    entprell(20); // schalter entprellen
risingedgetimer  ton(500);     // steigende flanke wird verzoegert
fallingedgetimer toff(500);    // abfallende flanke wird verzoegert
 
void setup(void)
{
  pinmode(s1,input_pullup);
  pinmode(out1,output);
  pinmode(out2,output);
}

void loop(void)
{
  bool schalter = entprell(!digitalread(s1)); // invers wg. pullup
  digitalwrite(out1, toff(schalter));
  digitalwrite(out2, ton(schalter));
}



-------------------

zu guter letzt noch die combietimer.h in welcher die ganze magie steckt:
code: [select]
#pragma once

namespace combie
{
   
   
    class simpletimer
    {
      private:
      unsigned long timestamp = 0;
      bool abgelaufen = true; // default status: timer abgelaufen
   
      public:
      void start()
      {
        timestamp   = millis();
        abgelaufen  = false;
      }
   
      bool operator()(const unsigned long ablaufzeit)
      {
        if(!abgelaufen) abgelaufen = millis() - timestamp >= ablaufzeit;
        return abgelaufen;
      }
    };
   
   
    class pulsator   // liefert alle x ms einen high impuls
    {
      protected:
      simpletimer timer;
      unsigned long interval;
     
      public:
      pulsator(unsigned long interval):interval(interval){}
     
      void setinterval(const unsigned long _interval)
      {
         interval =  _interval;
      }

     
      void start()
      {
        timer.start();
      }
     
      operator bool()
      {
          bool result = false;
          if(timer(interval))
          {
            result = true;
            timer.start();
          }
          return result;
      }
    };
   
    class edgetimer     // die abstakte mutter der flankenverzoegerer
    {
      protected:
      simpletimer timer;
      unsigned long laufzeit = 0;
   
      public:
      explicit edgetimer(const unsigned long laufzeit):laufzeit(laufzeit){}
     
      virtual bool operator()(const bool trigger) = 0;
     
      void setlaufzeit(const unsigned long _laufzeit)
      {
         laufzeit =  _laufzeit;
      }
    };
   
    class fallingedgetimer: public edgetimer // abfallende flanke wird verzoegert
    {
      public:
      using edgetimer::edgetimer;
     
      virtual bool operator()(const bool trigger)
      {
        if(trigger) timer.start();
        return !timer(laufzeit);
      }
    };
   
    class risingedgetimer: public edgetimer // steigende flanke wird verzoegert
    {
      public:
      using edgetimer::edgetimer;
     
      virtual bool operator()(const bool trigger)
      {
        if(!trigger) timer.start();
        return timer(laufzeit);
      }
    };
   
    class entprelltimer
    {
      private:
      simpletimer timer;
      bool merker = false;  //  zustand
      const unsigned long entprellzeit;
     
      public:
      explicit entprelltimer(const unsigned long entprellzeit) : entprellzeit(entprellzeit)  {}
     
      bool operator()(const bool trigger)
      {
         if(merker == trigger)   timer.start();
         if(timer(entprellzeit)) merker = !merker;
         return merker;
      }
    };
   
}



die combietimer.h kann man einfach mit ins projektverzeichnis werfen und wird dann von arduino in einem tab angezeigt.




vorschläge?
ansichten?
kritik?
würde mich freuen!

sieht gut aus :)


der bool operator in edgetimer sollte abstrakt sein. im kommentator schreibst du auch dass dass sein soll:
code: [select]

virtual bool operator()(const bool trigger) = 0;

in c++ nennt sich das auch "pure virtual function"


Arduino Forum > International > Deutsch (Moderator: uwefed) > [Projekt] INTERVAL Ersatzstoff


arduino

Comments

Popular posts from this blog

Error compiling for board Arduino/Genuino Uno.

Installation database is corrupt

esp8266 (nodemcu 0.9) client.write très lent ???