Go Down

Topic: wenn taste X sekunden gedrückt dann für X sekunden ausgang HIGH (Read 1 time) previous topic - next topic

arcaine

:smiley-mr-green:
Endlicher Automat = Schrittkette = finite state machine = eine endliche Zahl Zustände verarbeiten

Eine Realisierung geht beispielsweise mit switch/case.

Die Aufgabe ruft auch nach einer Struktur oder Klasse, weil dann zusammengehörige Daten zusammenstehen. (Wo habe ich das nur schon mal gelesen ;D ). Nach einer Anregung von combie als Diskussionsgrundlage:

Code: [Select]
#define LEDSCHALTZEIT 1000

class Taster
{
    const byte tasterPin, ledPin;
    const uint32_t tastMinzeit, ledAn;
    uint32_t tastMillis, ledMillis;
    bool tastNeu, tastAlt;
    byte schritt;
  public:
    Taster(const byte tasterPin, const byte ledPin, const uint32_t tastMinzeit):
      tasterPin(tasterPin), ledPin(ledPin), tastMinzeit(tastMinzeit), ledAn(LEDSCHALTZEIT), tastMillis(), ledMillis(0), tastNeu(0), tastAlt(), schritt(0) {}

    void init() //Initialisierung
    {
      digitalWrite(ledPin, HIGH);
      pinMode (ledPin, OUTPUT);
      pinMode (tasterPin, INPUT_PULLUP);
      tastAlt = digitalRead(tasterPin);
    }

    enum {WARTEN, MINZEIT, LEDZEIT};

    void run()
    {
      uint32_t jetzt = millis();
      tastAlt = tastNeu;
      tastNeu = digitalRead(tasterPin);
      switch (schritt)
      {
        case WARTEN:
          if (tastAlt && !tastNeu)
          {
            tastMillis = jetzt;
            schritt = MINZEIT;
          }
          break;
        case MINZEIT:
          if ((jetzt - tastMillis >= tastMinzeit))
          {
            if (!tastNeu)
            {
              digitalWrite(ledPin, LOW);
              ledMillis = jetzt;
              schritt = LEDZEIT;
            } else {
              schritt = WARTEN;
            }
          }
          break;
        case LEDZEIT:
          if (jetzt - ledMillis >= ledAn)
          {
            digitalWrite(ledPin, HIGH);
            schritt = WARTEN;
          }
          break;
      }
    }
};

Taster taster []
{ //tasterPin, ledPin, tastMinzeit
  {         2,      9,         30}, // gelb
  {         3,     10,         30}, // rot
  {         4,     11,         30}, // gruen
  {         5,     12,         30}, // blau
  {         6,     13,       2000}  // weiß
};

void setup()
{
  for (Taster &t : taster) t.init();
}

void loop()
{
  for (Taster &t : taster) t.run();
}


Fantastisch! Danke!!!

combie

Die Aufgabe ruft auch nach einer Struktur oder Klasse, weil dann zusammengehörige Daten zusammenstehen. (Wo habe ich das nur schon mal gelesen ;D ). Nach einer Anregung von combie als Diskussionsgrundlage:
Ich habe mir das mal aufmerksam angesehen.

Es gibt dort 2 Dinge, welche aus meiner Sicht verbesserungswürdig sind.

Einmal das magische Define "#define LEDSCHALTZEIT 1000".
Das verbessere ich mal nicht großartig, denn das tuning ist eher trivial. Einfach ein weiterer Konstruktor Parameter.

Der zweite Punkt betrifft den "schritt". Das Tuning ist nicht ganz so trivial.
Erstmal sollte es begrenzt werden, auf die tatsächlich möglichen Schritte.
Denn bisher könnte man auf die Idee kommen mit schritt++ einfach einen weiter zu gehen, was wegen des fehlenden default: Zweigs zu einem Problem werden könnte.
Ebenso wird eine Initialisierung/Zuweisung, z.B. so: schritt = PI; nicht unterbunden
Ansonsten finde ich die Idee, die Schritte auf byte zu begrenzen zu wollen voll OK.
Die magische Null bei der Initialisierung darf auch unterbunden werden.


Die Verbesserung findet sich im folgenden.
a. schritt und alles damit zusammenhängende, auf 8 Bit begrenzt
b. schritt ist jetzt vollkommen Typesicher
c. das #define entsorgt, aber die Funktionalität nicht verändert
d. ein paar Nullen bei der Konstruktorinitialisierungsliste hinzugefügt(Kosmetik(?!))

Code: [Select]

constexpr uint32_t LEDSCHALTZEIT = 1000;

class Taster
{
  private:
    enum class Schritt:byte {WARTEN, MINZEIT, LEDZEIT};
    const byte tasterPin, ledPin;
    const uint32_t tastMinzeit, ledAn;
    uint32_t tastMillis, ledMillis;
    bool tastNeu, tastAlt;
    Schritt schritt;
  public:
    Taster(const byte tasterPin, const byte ledPin, const uint32_t tastMinzeit):
      tasterPin(tasterPin), ledPin(ledPin), tastMinzeit(tastMinzeit), ledAn(LEDSCHALTZEIT), tastMillis(0), ledMillis(0), tastNeu(0), tastAlt(0), schritt(Schritt::WARTEN) {}

    void init() //Initialisierung
    {
      digitalWrite(ledPin, HIGH);
      pinMode (ledPin, OUTPUT);
      pinMode (tasterPin, INPUT_PULLUP);
      tastAlt = digitalRead(tasterPin);
    }


    void run()
    {
      uint32_t jetzt = millis();
      tastAlt = tastNeu;
      tastNeu = digitalRead(tasterPin);
      switch (schritt)
      {         case Schritt::WARTEN:
          if (tastAlt && !tastNeu)
          {
            tastMillis = jetzt;
            schritt = Schritt::MINZEIT;
          }
          break;
        case Schritt::MINZEIT:
          if ((jetzt - tastMillis >= tastMinzeit))
          {
            if (!tastNeu)
            {
              digitalWrite(ledPin, LOW);
              ledMillis = jetzt;
              schritt = Schritt::LEDZEIT;
            } else {
              schritt = Schritt::WARTEN;
            }
          }
          break;
        case Schritt::LEDZEIT:
          if (jetzt - ledMillis >= ledAn)
          {
            digitalWrite(ledPin, HIGH);
            schritt = Schritt::WARTEN;
          }
          break;
      }
    }
};

Taster taster []
{ //tasterPin, ledPin, tastMinzeit
  {         2,      9,         30}, // gelb
  {         3,     10,         30}, // rot
  {         4,     11,         30}, // gruen
  {         5,     12,         30}, // blau
  {         6,     13,       2000}  // weiß
};

void setup()
{
  for (Taster &t : taster) t.init();
}

void loop()
{
  for (Taster &t : taster) t.run();
}


Wie man sieht, keine Welt bewegenden Änderungen .....
Im Grunde alles beim alten.
Heute war Gestern Morgen.
Heute ist Morgen Gestern.
Morgen ist Heute Gestern.
Gestern war Heute Morgen

arcaine

Ich habe mir das mal aufmerksam angesehen.

Es gibt dort 2 Dinge, welche aus meiner Sicht verbesserungswürdig sind.

Einmal das magische Define "#define LEDSCHALTZEIT 1000".
Das verbessere ich mal nicht großartig, denn das tuning ist eher trivial. Einfach ein weiterer Konstruktor Parameter.

Der zweite Punkt betrifft den "schritt". Das Tuning ist nicht ganz so trivial.
Erstmal sollte es begrenzt werden, auf die tatsächlich möglichen Schritte.
Denn bisher könnte man auf die Idee kommen mit schritt++ einfach einen weiter zu gehen, was wegen des fehlenden default: Zweigs zu einem Problem werden könnte.
Ebenso wird eine Initialisierung/Zuweisung, z.B. so: schritt = PI; nicht unterbunden
Ansonsten finde ich die Idee, die Schritte auf byte zu begrenzen zu wollen voll OK.
Die magische Null bei der Initialisierung darf auch unterbunden werden.


Die Verbesserung findet sich im folgenden.
a. schritt und alles damit zusammenhängende, auf 8 Bit begrenzt
b. schritt ist jetzt vollkommen Typesicher
c. das #define entsorgt, aber die Funktionalität nicht verändert
d. ein paar Nullen bei der Konstruktorinitialisierungsliste hinzugefügt(Kosmetik(?!))

Code: [Select]

constexpr uint32_t LEDSCHALTZEIT = 1000;

class Taster
{
  private:
    enum class Schritt:byte {WARTEN, MINZEIT, LEDZEIT};
    const byte tasterPin, ledPin;
    const uint32_t tastMinzeit, ledAn;
    uint32_t tastMillis, ledMillis;
    bool tastNeu, tastAlt;
    Schritt schritt;
  public:
    Taster(const byte tasterPin, const byte ledPin, const uint32_t tastMinzeit):
      tasterPin(tasterPin), ledPin(ledPin), tastMinzeit(tastMinzeit), ledAn(LEDSCHALTZEIT), tastMillis(0), ledMillis(0), tastNeu(0), tastAlt(0), schritt(Schritt::WARTEN) {}

    void init() //Initialisierung
    {
      digitalWrite(ledPin, HIGH);
      pinMode (ledPin, OUTPUT);
      pinMode (tasterPin, INPUT_PULLUP);
      tastAlt = digitalRead(tasterPin);
    }


    void run()
    {
      uint32_t jetzt = millis();
      tastAlt = tastNeu;
      tastNeu = digitalRead(tasterPin);
      switch (schritt)
      {         case Schritt::WARTEN:
          if (tastAlt && !tastNeu)
          {
            tastMillis = jetzt;
            schritt = Schritt::MINZEIT;
          }
          break;
        case Schritt::MINZEIT:
          if ((jetzt - tastMillis >= tastMinzeit))
          {
            if (!tastNeu)
            {
              digitalWrite(ledPin, LOW);
              ledMillis = jetzt;
              schritt = Schritt::LEDZEIT;
            } else {
              schritt = Schritt::WARTEN;
            }
          }
          break;
        case Schritt::LEDZEIT:
          if (jetzt - ledMillis >= ledAn)
          {
            digitalWrite(ledPin, HIGH);
            schritt = Schritt::WARTEN;
          }
          break;
      }
    }
};

Taster taster []
{ //tasterPin, ledPin, tastMinzeit
  {         2,      9,         30}, // gelb
  {         3,     10,         30}, // rot
  {         4,     11,         30}, // gruen
  {         5,     12,         30}, // blau
  {         6,     13,       2000}  // weiß
};

void setup()
{
  for (Taster &t : taster) t.init();
}

void loop()
{
  for (Taster &t : taster) t.run();
}


Wie man sieht, keine Welt bewegenden Änderungen .....
Im Grunde alles beim alten.

hallo liebe gemeinde, :D

am Wochenende hatte ich nun endlich wieder mal zeit für mein Projekt. ;D  ich habe es soweit fertig gestellt. 8)
Nur ist mir beim testen aufgefallen das beim Start des UNOs immer erstmal alle LEDs auf High sind und sie erst auf low geschalten werden wenn ich die tasten der jeweiligen led für die TastMinzeit betätige.
so als müsste man erst alles initialisieren. :smiley-eek:
leider erschließt sich mir aus dem Sketch nicht warum dies so ist!? :smiley-sad:
Hat jemand Tipps?

vielen dank im voraus  ;)

Peter-CAD-HST

Moin arcaine,
in der INIT muss der Wert für ledPin = LOW geschrieben werden.
Code: [Select]
void init() //Initialisierung
    {
      digitalWrite(ledPin, LOW);
      pinMode (ledPin, OUTPUT);
      pinMode (tasterPin, INPUT_PULLUP);
      tastAlt = digitalRead(tasterPin);
    }

Gruss Peter
und gesund belieben
KISS Q&D - keep calm and carry on - mind the gap - beware of sharks! -

agmue

Ich habe mir das mal aufmerksam angesehen.
...
Im Grunde alles beim alten.
Danke!

Kürzlich suchte ich nach "enum class", jetzt habe ich es wiedergefunden. Dann will ich mal hoffen, beim nächsten Mal werde ich erneut fündig, ich wollte es eigentlich in meinen Standard übernehmen.

Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

arcaine

Moin arcaine,
in der INIT muss der Wert für ledPin = LOW geschrieben werden.
Code: [Select]
void init() //Initialisierung
    {
      digitalWrite(ledPin, LOW);
      pinMode (ledPin, OUTPUT);
      pinMode (tasterPin, INPUT_PULLUP);
      tastAlt = digitalRead(tasterPin);
    }

Gruss Peter
und gesund belieben
Dankeschön!

arcaine

Ahoi Gemeinde...

Die tastMillis liegen im Schnitt zwischen 100 und 2000. Die Pause variiert zwischen 1 und "endlos".

combie

Ja, das ist doch schön!
Oder?

Ansonsten ist mir dein Posting ein Rätsel.
(aber ich muss ja auch nicht alles verstehen)
Heute war Gestern Morgen.
Heute ist Morgen Gestern.
Morgen ist Heute Gestern.
Gestern war Heute Morgen

arcaine

leider ist das nur ein kleiner teil des eigentlichen Post ...
irgendwie geht immer nur dieser teil, denn Rest übernimmt es nicht.
über quick-Edit kommt dann "The message body was left empty." als Fehler ...

keine Ahnung warum das nicht geht

Tommy56

über quick-Edit kommt dann "The message body was left empty." als Fehler ...
Dann mach doch einfach ein Reply

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

arcaine

Ahoi Gemeinde...

Die tastMillis liegen im Schnitt zwischen 100 und 2000. Die Pause variiert zwischen 1 und "endlos".

arcaine

Dann mach doch einfach ein Reply

Gruß Tommy
wenn es funktionieren würde... mit handy das selbe problem...

Tommy56

Also mit "richtigen Rechnern" funktioniert es. Die mobilen Teile haben halt so ihre Probleme. Das ist aber nicht das Problem des Forums.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

arcaine

Ahoi Gemeinde...
Die tastMillis liegen im Schnitt zwischen 100 und 2000. Die Pause variiert zwischen 1 und "endlos".
Da die "tastMinzeit" >2500 ist sollte das meines Erachtens keine Problem darstellen!?

Dennoch habe ich folgendes Problem:
Bei vielen kurz aufeinander Folgenden Signalen (Aktuell ein induktiver Näherungssensor über einen optokoppler) schaltet der UNO die Led für die LEDSCHALTZEIT auf HIGH ohne das die eigentliche tastMinzeit durchgehend erreicht wurde.

ich habe versucht mit der LEDSCHALTZEIT sowie auch mit der tastMinzeit zu variieren, leider ohne Erfolg.

Jetzt hat es geklappt den ganzen Post zu Posten. Die Emojis waren vermutlich der Grund.

arcaine

Ich habe mir das mal aufmerksam angesehen.

Es gibt dort 2 Dinge, welche aus meiner Sicht verbesserungswürdig sind.

Einmal das magische Define "#define LEDSCHALTZEIT 1000".
Das verbessere ich mal nicht großartig, denn das tuning ist eher trivial. Einfach ein weiterer Konstruktor Parameter.

Der zweite Punkt betrifft den "schritt". Das Tuning ist nicht ganz so trivial.
Erstmal sollte es begrenzt werden, auf die tatsächlich möglichen Schritte.
Denn bisher könnte man auf die Idee kommen mit schritt++ einfach einen weiter zu gehen, was wegen des fehlenden default: Zweigs zu einem Problem werden könnte.
Ebenso wird eine Initialisierung/Zuweisung, z.B. so: schritt = PI; nicht unterbunden
Ansonsten finde ich die Idee, die Schritte auf byte zu begrenzen zu wollen voll OK.
Die magische Null bei der Initialisierung darf auch unterbunden werden.


Die Verbesserung findet sich im folgenden.
a. schritt und alles damit zusammenhängende, auf 8 Bit begrenzt
b. schritt ist jetzt vollkommen Typesicher
c. das #define entsorgt, aber die Funktionalität nicht verändert
d. ein paar Nullen bei der Konstruktorinitialisierungsliste hinzugefügt(Kosmetik(?!))

Code: [Select]

constexpr uint32_t LEDSCHALTZEIT = 1000;

class Taster
{
  private:
    enum class Schritt:byte {WARTEN, MINZEIT, LEDZEIT};
    const byte tasterPin, ledPin;
    const uint32_t tastMinzeit, ledAn;
    uint32_t tastMillis, ledMillis;
    bool tastNeu, tastAlt;
    Schritt schritt;
  public:
    Taster(const byte tasterPin, const byte ledPin, const uint32_t tastMinzeit):
      tasterPin(tasterPin), ledPin(ledPin), tastMinzeit(tastMinzeit), ledAn(LEDSCHALTZEIT), tastMillis(0), ledMillis(0), tastNeu(0), tastAlt(0), schritt(Schritt::WARTEN) {}

    void init() //Initialisierung
    {
      digitalWrite(ledPin, HIGH);
      pinMode (ledPin, OUTPUT);
      pinMode (tasterPin, INPUT_PULLUP);
      tastAlt = digitalRead(tasterPin);
    }


    void run()
    {
      uint32_t jetzt = millis();
      tastAlt = tastNeu;
      tastNeu = digitalRead(tasterPin);
      switch (schritt)
      {         case Schritt::WARTEN:
          if (tastAlt && !tastNeu)
          {
            tastMillis = jetzt;
            schritt = Schritt::MINZEIT;
          }
          break;
        case Schritt::MINZEIT:
          if ((jetzt - tastMillis >= tastMinzeit))
          {
            if (!tastNeu)
            {
              digitalWrite(ledPin, LOW);
              ledMillis = jetzt;
              schritt = Schritt::LEDZEIT;
            } else {
              schritt = Schritt::WARTEN;
            }
          }
          break;
        case Schritt::LEDZEIT:
          if (jetzt - ledMillis >= ledAn)
          {
            digitalWrite(ledPin, HIGH);
            schritt = Schritt::WARTEN;
          }
          break;
      }
    }
};

Taster taster []
{ //tasterPin, ledPin, tastMinzeit
  {         2,      9,         30}, // gelb
  {         3,     10,         30}, // rot
  {         4,     11,         30}, // gruen
  {         5,     12,         30}, // blau
  {         6,     13,       2000}  // weiß
};

void setup()
{
  for (Taster &t : taster) t.init();
}

void loop()
{
  for (Taster &t : taster) t.run();
}


Wie man sieht, keine Welt bewegenden Änderungen .....
Im Grunde alles beim alten.
Hallo,

Gibt es bei diesem Sketch einen mindest Zeitraum der zwischen den Signalen sein sollte? Was passiert wenn im selben Zeitraum zwei Signale von unterschiedlichen „Tastern" kommen?

Go Up