For - Loop ohne Delay verzögern

Hallo Leute!

Eine Frage ist es möglich eine For-Loop ohne ein Delay zu verzögern ? Ich habe schon mehrere Versuche gestartet mithilfe von Timer Funktionen, aber dabei ist nichts positives hervorgetreten.

Das ist der Code den ich umwandeln möchte, aber es einfach nicht geschafft habe.

void setup() {
 
  for (int thisPin = 40; thisPin < 60; thisPin++)  {
    pinMode(thisPin, OUTPUT);      
  }
}

void loop() {

  for (int thisPin = 40; thisPin < 60; thisPin++) { 
    digitalWrite(thisPin, HIGH);   
    delay(1000);                  
    digitalWrite(thisPin, LOW);    
  }

  for (int thisPin = 60; thisPin >= 40; thisPin--) { 
    digitalWrite(thisPin, HIGH);
    delay(1000);
    digitalWrite(thisPin, LOW);
  }
}

LG

Speedcore016:
Eine Frage ist es möglich eine For-Loop ohne ein Delay zu verzögern ?

Wenn es um die Vermeidung von delay() geht, fällt mir immer zuerst ein Konstrukt ein, das sich einen millis()-Wert merkt und dann immer wieder abfragt, ob die Differenz zum aktuellen Wert eine bestimmte Größe erreicht hat. So ein Konstrukt kannst Du prima zusätzlich in eine For-Schleife integrieren. Probleme sind mir dabei noch nie begegnet.

Ansonsten lohnt vielleicht ein Blick auf das, was ich zum Thema „endlicher Automat“ ins Netz gekippt habe (achte bei Bedarf auch auf die Folgeseite!)

Gruß

Gregor

ja, das kann man. Ob es sinnvoll ist, ist eine andere Frag.

Was willst du den mit dem Sketch machen, bzw. was soll er machen?

Eine Frage ist es möglich eine For-Loop ohne ein Delay zu verzögern ?

Hier: Multitasking Macros
Findest du eine Variante (in den Beispielen), wie man for() Schleifen unterbrechen/verzögern kann, um Zeit für andere Sachen frei zu schaufeln.
8) Es ist allerdings ein klein wenig "dreckig". 8)

Ich tendiere eher zu INTERVAL.h

ElEspanol:
Ich tendiere eher zu INTERVAL.h

Wie auch immer....

Das Problem muss im Kopf gelöst werden.

Alles andere sind nur Hilfsmittel, keine Lösungen.

combie:
Das Problem muss im Kopf gelöst werden.

und dich dabei von der for-Schleife lösen. Du hast bereits eine Schleife: den loop() - und die musst Du nutzen um dein Problem zu lösen.

Wenn ich deinen Code richtig interpretiere, dann willst du doch folgendes erreichen:

die Pins von 40 bis 60 werden nacheinander jeweils für 1 Sekunde auf HIGH gesetzt, dann in umgekehrter Reihenfolge wieder zurück.

Das ist quasi ein Lauflicht. Such doch mal nach "Lauflicht" oder "knight rider"

Das ist der Code an dem ich mich mit For - Loops beschäftige , den er ist simpel und verständlich. Durch die Einfachheit des Codes kann ich mich an Sachen heranführen welche mir nicht geläufig sind wie mein Problem mit dem Delay in der For-Loop, welches ich ersetzen möchte

den er ist simpel und verständlich

... führt dich aber in die Irre (oder eine Sackgasse).

Das Ziel ("ohne delay") ist doch, dass loop() so gut wie keine Zeit braucht.
Langsame Aktionen entstehen, indem du dir merkst, seit wann der aktuelle Zustand schon ansteht.
( Ausserdem wohl, welches der akteulle Zustand ist )

Da brauchst du, ausser loop() selbst, keine weiteren Schleifen.

  • delay ist für simple Demos

  • for-Schleifen sind gut, um gleichartige Aktionen in Serie (praktisch gleichzeitig) auszuführen (z.B. eine Liste von Pins auf OUTPUT zu setzen)

Die Frage ist, was willst du durch den Verzicht auf Delay erreichen. In deinem Beispiel ist der Verzicht auf eine For-Schleife und dafür alles in der Loop mit Hilfe von Statusvariablen der sinnvollste Weg.

Willst du auf die For-Schleife nicht verzichten, kannst du eine while-Schleife einschachteln.

Anstelle von Delay(1000) geht auch

unsigned long oldmillis=millis();
wihle (millis()-oldmillis<1000)
{ tue dies und das}

Wenn dann bitte so:

unsigned long nextMillis=millis()+1000;
while (millis() < nextMillis)
{ tue dies und das}

So muss nur einmal berechnet werden. In der vorherigen Variante findet die Addition jedes Mal statt.

@TE
Hier eine mögliche Lösung:

void loop() {
  static unsigned long nextMillis = 0;

  unsigned long currentMillis = millis();
  if (currentMillis > nextMillis) {
    nextMillis = currentMillis + 1000;
    light();
  }
}

void light() {
  static int currentPin = 40;
  static boolean pinState = LOW;
  
  pinState = !pinState;
  digitalWrite(currentPin, pinState);
  if (pinState == LOW) {
    currentPin++;
    if (currentPin > 59) {
      currentPin = 40;
    }
  }
}

light() wird jede Sekunde aufgerufen, ohne zu blockieren und kümmert sich selbst um das fortlaufen. Das wäre jetzt aber nur ein Lauflicht in eine Richtung. Die andere Richtung und den Wechsel darfst du dir selber ausdenken :wink:

Ich hab den Code direkt im Forum geschrieben, weiß also nicht ob er kompiliert. Kann durchaus noch Fehler haben.

Speedcore016:
Das ist der Code an dem ich mich mit For - Loops beschäftige , den er ist simpel und verständlich. Durch die Einfachheit des Codes kann ich mich an Sachen heranführen welche mir nicht geläufig sind wie mein Problem mit dem Delay in der For-Loop, welches ich ersetzen möchte

Dieser Ansatz ist aber komplizierter, als er auf den ersten Blick erscheint.

Du müsstest eigentlich erst mal definieren: Warum kein delay ?

Denn egal, was man mit einem Prozessor macht, er rennt (mal von Powersavings und von echtem "sleep" bei manchen Prozessorarchitekturen abgesehen) immer Vollgas, egal ob mit mit oder ohne delay().

Du kannst delay() deshalb nur umgehen, indem Du den Prozessor mit irgendwas anderem beschäftigst, denn er hält ja nicht an. Ist so ähnlich wie bei einem Flugzeug, das kann auch nicht anhalten, und muss ggf. Warteschleifen fliegen wenn es nicht weiter will.

Am Einfachsten wäre dabei so was

uint32_t count = 16000000;
while(--count)
    ;

Bei einem 16MHZ Board dauert diese Schleife ein paar Sekunden, da hat der Prozessor erst mal zu tun, bevor er weiter läuft. Das ist aber im Grunde nichts Anderes, als ein selbst gebasteltes delay(), das macht auch nichts Anderes.

Deshalb die Frage: Was genau soll der Verzicht auf delay() bewirken? Bevor das nicht klar ist, kann man schlecht weiter helfen. Vielleicht wolltest Du ja eigentlich was ganz anderes erreichen? Freie Prozessor-Zeit, vielleicht ?

Dann z.B. wäre ein ein völlig anderer, und auch durchaus anspruchsvoller Ansatz erforderlich.

while (millis() < nextMillis)
{ /*tue das hier immer wieder, bis die Sekunde vorbei ist. Sonst mache solange NICHTS */ }

Keine Ahnung wer sowas braucht und wofür.
Der Sinn scheint zu sein, dass "das hier" geringfügig schneller wiederholt wird als ein minimal-loop-Durchlauf braucht, und dafür solange die loop() totgelegt wird. "verzögern" würde ich das nicht nennen.

Dass man, auch wenn ein Sketch wohl nicht 49 Tage lang laufen wird, es aus Prinzip immer richtig rum machen sollte, und nicht so, lass ich jetzt mal unerwähnt. 8)

    nextMillis = currentMillis + 1000;

Das ist ein grober Fehler.

Ins besondere, in Verbindung mit dem darauf folgenden Vergleich.

TelosNox:
Wenn dann bitte so:

unsigned long nextMillis=millis()+1000;

while (millis() < nextMillis)
{ tue dies und das}




So muss nur einmal berechnet werden. In der vorherigen Variante findet die Addition jedes Mal statt.

Die Idee ist zwar verständlich, aber wenn es zum Überlauf von millis() kommt, dann rast die Schleife ohne Verzögerung durch. Also diese Lösung ist im Gegensatz zu meiner ungeeignet für lang laufende Projekte.

Eine Frage zu der Möglichkeit mit der Verwendung von millis(); statt delay.

Angenommen:

Ich habe eine For-Schleife, welche von 40 bis 60 hinaufzählt und pro Durchlauf der Schleife eine Addition von 1 auf die 40 hinzufügt, bis 60 erreicht ist. Und pro Durchlauf wird eine Leuchtdiode (40 dann 41 dann 42.....) eingeschalten (diese bleiben auch bis zum Ende auch eingeschalten) , um den Werdegang von 40 zu 60 zu symbolisieren. Ohne delay würde dieses hinaufzählen sehr sehr schnell fertig sein, und alle Leuchtdioden von 40 bis 60 würden sehr schnell eingeschalten werden ohne sichtbaren Verlauf. Aber! Ich möchte einen Verlauf erzeugen, und hierbei hilft das delay ( Wurde von mir bereits getestet) kann ich hier mir einfach mit dieser millis() Funktion helfen, um das selbe Ergebnis zu erzeugen ?

Der Sinn von millis() besteht darin dass du das Programm nicht komplett anhälst. delay() sorgt dafür dass an der Stelle alles stehen bleibt. Es gibt Anwendungen wo das ok ist. Aber das sind meistens sehr einfache Programme die nur eine Sache erledigen sollen.

delay() geht nicht mehr sobald mehrere Dinge nebeneinander ablaufen sollen. z.B. ein LED Muster ausgeben und während dessen Taster abfragen. Einfach well der Taster während der Verzögerungszeit nicht reagiert.

Speedcore016:
kann ich hier mir einfach mit dieser millis() Funktion helfen, um das selbe Ergebnis zu erzeugen ?

Du kannst natürlich mit der millis() Funktion ein delay() nachbilden. Nur - was bringt dir das?

Wie Serenifly schon schrieb, ist die Verwendung von millis() eigentlich für andere Zwecke gedacht - den 'quasi' gleichzeitigen Ablauf unterschiedlicher Aufgaben. Das geht mit deiner for-Schleife aber grundsätzlich nicht. Wenn Du während dem nacheinander Aufleuchten der Led's noch etwas anderes machen willst, musst Du es ohne die for-Schleife angehen.

Man kann eine for() Schleife verwenden!

Es ist natürlich doof, wenn die for() Schleife lange läuft, weil dann andere Dinge auf der Strecke bleiben.

2 Möglichkeiten gibt es um das zu verhindern...

  1. die Schleife ausrollen
    Das ist gut möglich aber arg abstrakt, da die for() Schleife dabei aus dem Code als solche verschwindet. Denn sie ist ja ausgerollt.

  2. Die for() Schleife mit einem Austiegs- und einem Wiedereintrittspunkt versehen. Das hat den Vorteil, dass sie als Schleife wiedererkennbar im Code bleibt, aber dann nicht mehr "so" funktioniert, wie man es gewohnt ist.