Mittwochs-Weekender: Automat ohne delay()

Hallo allerseits!

Durch den Blink-Thread bin ich darauf gekommen, dass sich mit dieser Fragestellung zwei Dinge erläutern lassen, die im Forum immer wieder auftauchen: Die Vermeidung von millis() delay() und das Modell eines „Endlichen Automaten“.

Ich habe also meinen im Thread genannten Code noch ein bisschen gepimpt und mit etwas Text garniert.

Was haltet Ihr hiervon?

Gruß

Gregor

Vielen Dank!!!!!!! Bei meinem Problem hilft es definitiv!!!!!!! Jetzt muss ich es nur noch auf meine Anwednung übertragen und hoffen, dass ich da keine Fehler mache :slight_smile:

MaHa76:
Vielen Dank!!!!!!! Bei meinem Problem hilft es definitiv!!!!!!! Jetzt muss ich es nur noch auf meine Anwednung übertragen und hoffen, dass ich da keine Fehler mache :slight_smile:

Freut mich! Wenn Dir beim Übertragen auf Deine Anwendung Dinge auffallen, die in meinem Geschreibsel besser sein könnten, gib bitte Bescheid!

Gruß

Gregor

Verbraucht die Abfrage von millis() nicht einige Takte? Es wird je Loop() fünf mal aufgerufen.
Optimal wäre es ja die millis direkt am Anfang der Loop in einer Variable zu speichern, statt an jeder Stelle neu abzufragen. Oder nicht?

Genau wie das hier:
d[0]+d[1]
d[0]+d[1]+d[2])
d[0]+d[1]+d[2]+d[3]

Diese drei festen Werte sollten in setup() vorberechnet werden, was noch mal einen Performancegewinn bringt. Hier werden bei 1000 loop durchläufen 6000 Berechnungen durchgeführt - die immer das selbe Ergebnis liefern. Zugriff auf Arrays dürfte zudem für den Arduino etwas unperformanter sein als der zugriff auf zb. eine normale long.

gregorss:
Die Vermeidung von millis() und das Modell eines „Endlichen Automaten“.

Du meinst Vermeidung von delay()?

Wenn Dir beim Übertragen auf Deine Anwendung Dinge auffallen, die in meinem Geschreibsel besser sein könnten, gib bitte Bescheid!

Darf ich auch?

OK, ich mach einfach mal:
Feine Beschreibung!

Nur, es ist ein endlicher Automat, und keine "Infinite State Machine", also nicht unendlich.
Denn: Die Anzahl möglicher Zustände ist begrenzt, also endlich.
Z.B. unser Universum wäre (höchstvermutlich) eine "Infinite State Machine", dessen mögliche Zustände scheinen unendlich zu sein. Zumindest für uns nicht zu überblicken.

Auch ein "Forth System" könnte man als Unendlich (aber trotzdem deterministisch) bezeichnen, denn dort kann man zur Laufzeit (auch automatisch) beliebig weitere Zustände hinzufügen. Begrenzt, nur durch die Speichermenge des Wirtssystems.

Die Anzahl Rundläufe spielt da keine Rolle, nur die Anzahl möglicher Zustände bestimmt die Endlichkeit.

Wenn du noch ein Attribut brauchst, dann nimm: "Deterministisch".
Du hast da einen "Deterministischen endlichen Automaten" gebaut.

AlphaRay:
Verbraucht die Abfrage von millis() nicht einige Takte? Es wird je Loop() fünf mal aufgerufen.
Optimal wäre es ja die millis direkt am Anfang der Loop in einer Variable zu speichern, statt an jeder Stelle neu abzufragen. Oder nicht?

Genau wie das hier:
d[0]+d[1]
d[0]+d[1]+d[2])
d[0]+d[1]+d[2]+d[3]

Diese drei festen Werte sollten in setup() vorberechnet werden, was noch mal einen Performancegewinn bringt. Hier werden bei 1000 loop durchläufen 6000 Berechnungen durchgeführt - die immer das selbe Ergebnis liefern. Zugriff auf Arrays dürfte zudem für den Arduino etwas unperformanter sein als der zugriff auf zb. eine normale long.

Danke für Deine Einwände!

Du hast natürlich recht. Mir kam es allerdings nicht auf den „optimalen“ Code an, sondern darauf, dass das von jemandem verstanden werden kann, der noch nicht allzu viel mit Arduino oder dem Programmieren zu tun hatte. Deshalb habe ich die „d“s dort hingeschrieben, wo es kaum übersehen werden kann und wo der Zusammenhang klar ist. Das „d“ hieß übrigens mal „duration“, was allerdings zu hässlichen ifs geführt hat.

Gruß

Gregor

combie:
Feine Beschreibung!

Könntest Du das noch ein paarmal schreiben? Das geht runter wie Öl :slight_smile:

combie:
Nur, es ist ein endlicher Automat, und keine "Infinite State Machine", also nicht unendlich.
Denn: Die Anzahl möglicher Zustände ist begrenzt, also endlich.
...
Die Anzahl Rundläufe spielt da keine Rolle, nur die Anzahl möglicher Zustände bestimmt die Endlichkeit.
...

Oha, offensichtlich habe ich „endlich“ und „nicht endlich“ anders interpretiert, als es in diesem Zusammenhang gemeint ist. Ich werde mein Getexte noch mal lesen und ggf. ändern.

Gruß

Gregor

Also... ich brauche einen endlichen Automaten... somit bin ich zufrieden damit... (wenn es da auch ist)

Die feste Reihenfolge wäre für mich hinderlich... das kann ich aber sicher umgehen... heute abend setze ich mich mal ran...

Hm...habs noch mal überflogen. Ich würde beim Start den millisMem nicht auf 0, sondern auf millis()+d[0] setzen.

Momentan ist millis() beim Start ja immer größer als millisMem, weshalb es vier Loop() durchläufe benötigt, bis millisMem endlich gesetzt wird.

Alternativ einfach setup():
phase=ON1; -> phase=OFF2;

Dadurch wird millisMem gesetzt + ON1 aktiviert - passt :wink:

AlphaRay:
Hm...habs noch mal überflogen. Ich würde beim Start den millisMem nicht auf 0, sondern auf millis()+d[0] setzen.

Momentan ist millis() beim Start ja immer größer als millisMem, weshalb es vier Loop() durchläufe benötigt, bis millisMem endlich gesetzt wird.

Alternativ einfach setup():
phase=ON1; -> phase=OFF2;

Dadurch wird millisMem gesetzt + ON1 aktiviert - passt :wink:

Das stimmt nicht so ganz. millisMem wird in Setup mit einer Null versorgt.

Gruß

Gregor

also bei mir funktioniert es nicht.... wobei ich min 5 AblaufStränge parallel laufen lasse...

MaHa76:
also bei mir funktioniert es nicht.... wobei ich min 5 AblaufStränge parallel laufen lasse...

Um sicher zu sein, dass mein Weekender-Code keinen Fehler enthält, habe ich ihn auf einem Nano getestet. Poste doch mal Deinen Code, vielleicht hast Du da einen Fehler drin, der mir sofort ins Auge springt.

Gruß

Gregor

gregorss:
Das stimmt nicht so ganz. millisMem wird in Setup mit einer Null versorgt.

Wird ja - ich habe nur geschrieben was er sollte :wink: Mit der aktuellen Einstellung braucht es vier Durchgänge:

  1. On1 -> geht in else...
  2. Off1 -> geht in else...
  3. On2 -> geht in else...
  4. Off2 -> erst hier wird millisMem zum ersten mal gesetzt + das ganze fängt an zu funktionieren. Bedarf insg. vier Loop-Durchläufe

Stellt man den Startwert so ein, springt er direkt da hin und millisMem wird gleich beim ersten Loop gesetzt:
phase=OFF2;

äähhmm....

Ich habe gerade gesehen:

millis()<millisMem+d[0]+d[1]+d[2]+d[3]

Das Verfahren erzeugt Überlaufprobleme.

Nachtrag: :o :o :o :o :o

// blinken  ohne delay 

#include <TaskMacro.h>
// Aus: https://forum.arduino.cc/index.php?topic=415229.0



const byte LEDPin=13; // Pin, an dem die LED haengt
const uint16_t d[]={10, 200, 10, 1000}; // Dauer der Phasen in ms

void setup()
{
  pinMode(LEDPin, OUTPUT);
}


void blinkTask()
{
  taskBegin();
  for(;;)
  {
    digitalWrite(LEDPin, HIGH);
    taskPause(d[0]);
    digitalWrite(LEDPin, LOW);
    taskPause(d[1]);
    digitalWrite(LEDPin, HIGH);
    taskPause(d[2]);
    digitalWrite(LEDPin, LOW);
    taskPause(d[3]);
  }
  taskEnd();
}


void loop()
{
   blinkTask();
}

Ich verlinke mal einfach zum passenden Beitrag: Ablaufsteuerung Nr. X ;-) (Feinschliff) - Deutsch - Arduino Forum

Ich muss aber sagen, dass deine Anleitung sehr gute Denkanstöße gegeben hat :slight_smile:

combie:
Ich habe gerade gesehen:Das Verfahren erzeugt Überlaufprobleme.

Danke für den Hinweis!

Kann man das Problem auf eine einfache Art vermeiden, d. h. ohne eine zusätzliche Bibliothek zu verwenden? Da mir spontan nichts eingefallen ist, habe ich eine entsprechende Warnung in meinen Weekender geschrieben.

Gruß

Gregor

millis()-millisMem > d[0]+d[1]+d[2]+d[3]

combie:

millis()-millisMem > d[0]+d[1]+d[2]+d[3]

Uh ... oh ... kein Wunder, dass ich nicht darauf gekommen bin. Das ist zu einfach.

Danke!

Gregor

:slight_smile: