Delay mit Millis ersetzen

Hallo,

ich möchte ein Lauflicht mit 4 LEDs mit millis steuern. Das lauflicht soll so ablaufen:

LED1 an
Zeit x
LED1 aus und LED2 an
Zeit x
LED2 aus und LED3 an
Zeit x
LED3 aus und LED4 an
Zeit x
LED4 aus und LED1 an

danach geht es immer weiter. Während das läuft, sollen noch andere LEDs an und aus gehen bzw. eine LED soll pulsieren.
Im Moment habe ich Probleme mit den ersten 4 LEDs.
Habe es hiermit versucht:

void loop()
{

  if (millis() - previousMillis1 > interval1)
  {
 previousMillis1 = millis();   // aktuelle Zeit abspeichern
 
    // Wert auf den Ausgang schreiben
 digitalWrite(13, HIGH);
  }
  
  if (millis() - previousMillis2 > interval2)
  {
 previousMillis2 = millis();   // aktuelle Zeit abspeichern
 
    // Wert auf den Ausgang schreiben
 digitalWrite(13, LOW);
 digitalWrite(12, HIGH);
  }
   
  if (millis() - previousMillis3 > interval3)
  {
 previousMillis3 = millis();   // aktuelle Zeit abspeichern
 
    // Wert auf den Ausgang schreiben
 digitalWrite(12, LOW);
 digitalWrite(11, HIGH);
  }

  if (millis() - previousMillis4 > interval4)
  {
 previousMillis4 = millis();   // aktuelle Zeit abspeichern
 
    // Wert auf den Ausgang schreiben
 digitalWrite(11, LOW);
 digitalWrite(10, HIGH);
  }


}

Kann mir da jemand helfen?

Vielen Dank und einen schönen Abend,

srkonus

Investier 10 Minuten in Google und du hast die Lösung

ElEspanol:
Investier 10 Minuten in Google und du hast die Lösung

Danke für die Antwort, sitze schon den ganzen Abend dran :frowning:

Nimm ein Array für die Pins. Iteriere über das Array, schalte alle zuerst aus und dann das nächste an. Am Ende stellst du den index wieder auf 0

Schau Dir BlinkWithoutDelay und zum Verständnis die Nachtwächtererklärung (kein Witz) an.

Gruß Tommy

danach geht es immer weiter.

Wenn du einen Gesamt-Zyklus hast, rechne doch einfach alles relativ dazu. (Nachdem du BlinkWithoutDelay verstanden hast)

const unsigned long gesamtzyklus= 30*1000L; // 30 sec, danach alles von vorne

if ( millis() - start >= gesamtzyklus ) start = millis();
unsigned long phase = millis() - start;  // phase ist immer im Bereich 0 .. gesamtzyklus
if (phase < 1000) digitalWrite(LED1, HIGH); // Beispiel
...

Merke: delay() wird nicht durch millis() ersetzt, der Sketch wird ganz anders:
Statt quälend langsam wird ein loop() - Durchlauf unendlich schnell.

Ablaufsteuerung

Meine Standardantwort zu Ablaufsteuerungen:
Eine Stichworte Sammlung für Google Suchen:
Endlicher Automat,
State Machine,
Multitasking,
Coroutinen,
Ablaufsteuerung,
Schrittkette,
BlinkWithoutDelay,

Blink Without Delay
Der Wachmann

Multitasking Macros
Intervall Macros

srkonus:
ich möchte ein Lauflicht mit 4 LEDs mit millis steuern. Das lauflicht soll so ablaufen:

LED1 an
Zeit x
LED1 aus und LED2 an
Zeit x
LED2 aus und LED3 an
Zeit x
LED3 aus und LED4 an
Zeit x
LED4 aus und LED1 an

danach geht es immer weiter. Während das läuft, sollen noch andere LEDs an und aus gehen bzw. eine LED soll pulsieren.
Im Moment habe ich Probleme mit den ersten 4 LEDs.
Habe es hiermit versucht:

Ich habe es mal so versucht:

const byte ledPins[]={2,3,4,5};
const byte NUMLEDS=sizeof(ledPins);

byte activeLED=0;

void setup() 
{
  Serial.begin(9600);  
  for(int i=0;i<NUMLEDS;i++) pinMode(ledPins[i],OUTPUT);
}

void showLeds()
{
  for (int i=0;i<NUMLEDS;i++)
  {
   if(i==activeLED) Serial.print('1'); else Serial.print('0');
  }
  Serial.println();
}


unsigned long lastTime,interval=2000;


void loop() 
{
 long  now=millis();
  if (now-lastTime>=interval)
  {
     lastTime=now;
     activeLED++;
     if (activeLED>= NUMLEDS) activeLED=0;
     showLeds();
  }
}

Dieses Beispielprogramm macht nur eine Debug-Ausgabe auf dem seriellen Monitor.

Findest Du selbst heraus, wie Du die Funktion showLeds ändern mußt,
damit die Pins entsprechend der gerade aktiven LED (activeLED) gesetzt werden?

jurs:
Ich habe es mal so versucht:

const byte ledPins[]={2,3,4,5};

const byte NUMLEDS=sizeof(ledPins);

byte activeLED=0;

void setup()
{
  Serial.begin(9600); 
  for(int i=0;i<NUMLEDS;i++) pinMode(ledPins[i],OUTPUT);
}

void showLeds()
{
  for (int i=0;i<NUMLEDS;i++)
  {
  if(i==activeLED) Serial.print('1'); else Serial.print('0');
  }
  Serial.println();
}

unsigned long lastTime,interval=2000;

void loop()
{
long  now=millis();
  if (now-lastTime>=interval)
  {
    lastTime=now;
    activeLED++;
    if (activeLED>= NUMLEDS) activeLED=0;
    showLeds();
  }
}




Dieses Beispielprogramm macht nur eine Debug-Ausgabe auf dem seriellen Monitor.

Findest Du selbst heraus, wie Du die Funktion showLeds ändern mußt,
damit die Pins entsprechend der gerade aktiven LED (activeLED) gesetzt werden?

Mit Deinem Beispiel konnte ich gar nichts anfangen, sorry.

Dann kannst du mit meinem Rat auch aus Post #3 auch nichts anfangen, weil das was jurs gemacht hat, ist so ähnlich, nur viel eleganter.

Analysier mal jurs Code genau, kannst viel dabei lernen.

Wie stufst du deine Arduino Programmierkenntnisse ein?

ElEspanol:
Dann kannst du mit meinem Rat auch aus Post #3 auch nichts anfangen, weil das was jurs gemacht hat, ist so ähnlich, nur viel eleganter.

Analysier mal jurs Code genau, kannst viel dabei lernen.

Wie stufst du deine Arduino Programmierkenntnisse ein?

Frischling, blutiger Anfänger

Habe jetzt das hier, das funktioniert, nur von der LED4 zu 1 ist unschön. Ein delay kommt mir da in den Sinn, will es aber nicht nutzen.
Werde morgen wohl mal ein Struktugram malen.

byte ledPin1 = 13;                  // LED liegt am (digitalen) Pin 13
byte ledPin2 = 12;
byte ledPin3 = 11;
byte ledPin3 = 10;

//boolean value1 = LOW;                  // Startwert der LED
//boolean value2 = LOW;
//boolean value3 = LOW;
boolean value4 = LOW

unsigned long previousMillis1 = 0;     // speichert wie viele Sekunden seit derletzten Änderung vergangen sind
unsigned long interval1 = 1;           // Interval zwischen zwei Änderungen

unsigned long previousMillis2 = 0;     // speichert wie viele Sekunden seit derletzten Änderung vergangen sind
unsigned long interval2 = 2;           // Interval zwischen zwei Änderungen

unsigned long previousMillis3 = 0;     // speichert wie viele Sekunden seit derletzten Änderung vergangen sind
unsigned long interval3 = 3;           // Interval zwischen zwei Änderungen

unsigned long previousMillis4 = 0;     // speichert wie viele Sekunden seit derletzten Änderung vergangen sind
unsigned long interval4 = 4;           // Interval zwischen zwei Änderungen

void setup()
{
    pinMode(13, OUTPUT);      // Setzt den ledPin (Pin 13) als Ausgang
    pinMode(12, OUTPUT);
    pinMode(11, OUTPUT);
    pinMode(10, OUTPUT);
}

void loop()
{

  if (millis() - previousMillis1 > interval1 && value4 == LOW)
  {
        previousMillis1 = millis();   // aktuelle Zeit abspeichern
        
    // Wert auf den Ausgang schreiben
        digitalWrite(10, LOW);
        digitalWrite(13, HIGH);
        value4 = HIGH;
  }
  
  if (millis() - previousMillis2 > interval2)
  {
        previousMillis2 = millis();   // aktuelle Zeit abspeichern
        
    // Wert auf den Ausgang schreiben
        digitalWrite(13, LOW);
        digitalWrite(12, HIGH);
  }
   
  if (millis() - previousMillis3 > interval3)
  {
        previousMillis3 = millis();   // aktuelle Zeit abspeichern
        
    // Wert auf den Ausgang schreiben
        digitalWrite(12, LOW);
        digitalWrite(11, HIGH);
  }

  if (millis() - previousMillis4 > interval4)
  {
        previousMillis4 = millis();   // aktuelle Zeit abspeichern
    // Wert auf den Ausgang schreiben
        digitalWrite(11, LOW);
        digitalWrite(10, HIGH);
        value4 = LOW;
  }


}

Willst du nur das Lauflicht haben oder in "Arduino einsteigen"?

Es geht auch etwas einfacher:

const byte leds[] = {13, 13, 12, 11, 10, 13};
uint32_t previousMillis, intervall = 500;
byte led;

void setup() {
  for (led = 0; led < sizeof(leds); led++) {
    pinMode(leds[led], OUTPUT);
  }
  led = 0;
}

void loop()
{
  if (millis() - previousMillis > intervall)
  {
    previousMillis = millis();          // aktuelle Zeit abspeichern
    digitalWrite(leds[led], LOW);       // LED aus
    digitalWrite(leds[led + 1], HIGH);  // LED ein
    if (led < sizeof(leds) - 2) {
      led++;
    } else {
      led = 1;
    }
  }
}

srkonus:
Frischling, blutiger Anfänger

Einfacher? Hast du das denn nicht gelesen?

ElEspanol:
Einfacher? Hast du das denn nicht gelesen?

Gelesen ja, aber meine Vorstellungskraft reicht nicht um ein Array da einzubauen. Die Antwort von agmue und die Wachmannsache werde ich morgen mal studieren.
Ich will nur einen Proton Pack für Karneval mit dem Arduino steuern und nicht tiefer einsteigen.

srkonus:
Mit Deinem Beispiel konnte ich gar nichts anfangen, sorry.

Gar nichts? Konntest Du nicht mal erkennen, an welchen vier Pins die LEDs als Lauflicht angesteuert werden sollen?
Also die vier Pins für die LEDs als OUTPUT schreibe ich Dir nochmal extra raus:

const byte ledPins[]={2,3,4,5};

Kannst Du im seriellen Monitor erkennen, wie da alle zwei Sekunden eine neue Zeile mit vier Zahlen ausgegeben wird, drei Nullen (für die ausgeschalteten LEDs) und eine eins (für die eingeschaltete LED), und die '1' springt alle zwei Sekunden immer eine Stelle nach rechts, bis sie von der vierten STelle an die erste Stelle springt.

Darin kannst Du keine Lauflicht-Programmlogik erkennen?

Na ja, ich glaube, dann kann ich Dir auch überhaupt nicht weiterhelfen.

ElEspanol:
Einfacher? Hast du das denn nicht gelesen?

Nee, da war ich gerade am Programmieren. Sagen wir so, #13 hat weniger Zeilen als #11, auch weniger Variablen. Das meinte ich mit "einfacher".

Aber möglicherweise ist ja ein endlicher Automat einfacher im Sinne von verständlicher:

const byte leds[] = {13, 12, 11, 10};
uint32_t previousMillis, intervall = 500;
byte led;

void setup() {
  for (led = 0; led < sizeof(leds); led++) {
    pinMode(leds[led], OUTPUT);
  }
  led = 0;
}

void loop()
{
  if (millis() - previousMillis > intervall)
  {
    previousMillis = millis();          // aktuelle Zeit abspeichern
    switch (led) {
      case 0:
        digitalWrite(leds[3], LOW);       // LED aus
        digitalWrite(leds[0], HIGH);      // LED ein
        break;
      case 1:
      case 2:
      case 3:
        digitalWrite(leds[led - 1], LOW);   // LED aus
        digitalWrite(leds[led], HIGH);      // LED ein
        break;
    }
    led++;
    led = led % sizeof(leds);
  }
}

Wobei es auch ohne switch/case geht:

const byte leds[] = {13, 12, 11, 10};
uint32_t previousMillis, intervall = 500;
byte led;
const byte anz = sizeof(leds);

void setup() {
  for (led = 0; led < sizeof(leds); led++) {
    pinMode(leds[led], OUTPUT);
  }
  led = 0;
}

void loop()
{
  if (millis() - previousMillis > intervall)
  {
    previousMillis = millis();          // aktuelle Zeit abspeichern
    if (!led) {
      digitalWrite(leds[anz - 1], LOW);   // LED aus
      digitalWrite(leds[0], HIGH);        // LED ein
    } else {
      digitalWrite(leds[led - 1], LOW);   // LED aus
      digitalWrite(leds[led], HIGH);      // LED ein
    }
    led++;
    led = led % anz;
  }
}

srkonus:
Ich will nur einen Proton Pack für Karneval mit dem Arduino steuern und nicht tiefer einsteigen.

Dann nimm den fertigen Code aus dem vorigen Post.

const byte leds[] = {13, 12, 11, 10};
diese Zeile musst du ggf. ändern und die tatsächlich verwendeten Pins eintragen. Du bist nicht auf 4 beschränkt, es gehen auch mehr.