Verzögerung ohne delay im Unterprogramm

Meine 4 Sprenger werden in einer Schleife nacheinander ein/ausgeschalten.
Wenn Sprenger1 an dann Sprenger4 aus.

Nun kann mein Sender aber nicht 2 Befehle gleichzeitig senden. Daher benötige ich eine Verzögerung von ca 3sec.

Also theoretisch so:

// functions to be called when an alarm triggers:
void Sprenger1(){
  Serial.println("Sprenger1Ost an & Sprenger4Nord aus");
  //Sprenger1 an
  Ausgangsnummer=2;
  trigger();
  //Sprenger4 aus
  delay(3000);
  Ausgangsnummer=0;
  trigger();  
}

Im Hintergrund läuft die akt. Uhrzeit. Da könnte man auch die Sekunden abfragen und 3sec abwarten - aber das wäre ja auch nix anderes als delay.

Das gepostete Unterprogramm wird durch ein Alarm.alarmrepeat der AlarmTime Library aufgerufen. Da gäbe es noch die Möglichkeit auch für das "ausschalten" einen extra Alarm zu setzen. Hmmm, naja: Unmengen an Alarmen.
Weiterhin könnte man noch zur Zeit des "Sprenger1 an" einen Einmalalarm Alarm.once für das "Sprenger4 aus" setzen. (momentan mein Favorit)

Gibt es noch elegantere Möglichkeiten um das blockierende Delay zu vermeiden?

Setzte in der Alarm Funktion nur eine Variable, dass ein Alarm ausgelöst wurde. Auf die kannst du dann in loop() abfragen und die Verzögerung a la BlinkWithoutDelay machen

Sieh dir mal "SimpleTimer" an, ich denke da kannst du deine Wartezeiten auf Basis von millis erschlagen.

Das habe ich jetzt beides nicht verstanden.

Mit den millis hatt ichs bisher noch nicht so. Muß ich mir mal näher ansehen...

Eine anschauliche Erklärung, wie millis() verwendet werden. Oder wenn Du magst Anleitung Ein Endlicher Automat entsteht.

stoni99:
Das habe ich jetzt beides nicht verstanden.

Mit den millis hatt ichs bisher noch nicht so. Muß ich mir mal näher ansehen...

Ja, ok. Das solltest du machen. Wenn du es mit millis erledigst, dann ist das ok. Die Library kannst du später immer noch einsetzen.
Wenn man das einmal drauf hat, ist es garnicht so kompliziert.

Wenn ich deine Sprengerei richtig verstanden habe, darf nur ein Sprenger laufen. Warum schaltest du nicht alle anderen aus, wenn der Alarm für den nächsten kommt?

Es geht auch darum, dass der Sprenger für eine bestimmte Zeit laufen muss. Aber die Funktion wird nur einmal aufgerufen. Statt also auch einen Alarm für die Endzeit zu setzen, kann man in der Alarm Funktion nur eine Status Variable setzen und macht dann die eigentliche Verzögerung in einer Funktion die man selbst ständig aufrufen kann.

Die "Wachmann-Geschichte" ist ja Klasse...

Hab ich das jetzt richtig verstanden:

Im void loop() lass ich die millis Zählung immer mit laufen.

Wenn ein Sprenger1 "an" Ereignis im Unterprogramm stattfindet setze ich dort eine globale Variable auf on.
Auf diese teste ich im milli-loop und schalte dann Sprenger4 3s später aus.

Müsste ich ja für jeden Sprenger einen eigenen "milli" im loop laufen lassen... :o

stoni99:
Müsste ich ja für jeden Sprenger einen eigenen "milli" im loop laufen lassen... :o

Nur wenn du alle Pumpen unabhängig schalten willst. Wenn immer nur eine auf einmal an ist reicht auch eine einzige Zeit-Variable.

Man kann das auch bequem mit Arrays und for-Schleifen erledigen. Alle Pins in ein Array. Ein Array für den Einschaltzeitpunkt (d.h. millis() beim Einschalten). Und eines für das Intervall. Dann nimmt man Einschaltzeitpunkt == 0 für AUS und > 0 für ein. Und kann jede Pumpe getrennt schalten.

Im void loop() lass ich die millis Zählung immer mit laufen.

Millis() läuft immer, auch unabhängig von loop()

für jeden Sprenger einen eigenen "milli" im loop laufen lassen

Es gibt nur einen milli Sekunden Spender.
Das reicht auch.

Seufzzzz, ich tu mich noch schwer mit den millis - muß ich mich mal gesondert damit beschäftigen.

Da eh TimeAlarm lib drin ist, hab es jetzt mit:

void Sprenger2(){
Serial.println("Sprenger2 Sued an");
Ausgangsnummer=2; //Sprenger2 an
trigger();
Alarm.timerOnce(3, Sprenger1aus); // einmalig nach 3s Sprenger1 aus
}

gemacht.
Ich glaube: TimeAlarm nutzt ja auch die milli Geschichte!?

Funktioniert prima.

stoni99:
Funktioniert prima.

Schade, da komme ich mit meinem Vorschlag wohl zu spät :frowning: aber wenn es Dich doch noch interessiert, hier ein endlicher Automat mit millis:

unsigned long aktMillis;
unsigned long prevMillis;
const int intervall = 3000;
enum Zustaende {WARTEN, S1AN, S2AN, S1AUS, S3AN, S2AUS};
byte zustand = WARTEN;

void setup() {
  Serial.begin(9600);
  Serial.println("Programmanfang");
}

void loop() {
  aktMillis = millis();
  bool weiter = false;
  if (Serial.available()) {
    char zeichen = Serial.read();
    weiter = true;
  }
  switch (zustand) {
    case WARTEN:
      if (weiter) {
        zustand = S1AN;
        Serial.println("Sprenger1 an");
      }
      break;
    case S1AN:
      if (weiter) {
        zustand = S2AN;
        prevMillis = aktMillis;
        Serial.println("Sprenger2 an");
      }
      break;
    case S2AN:
      if (aktMillis - prevMillis >= intervall) {
        zustand = S1AUS;
        Serial.println("Sprenger1 aus");
      }
      break;
    case S1AUS:
      if (weiter) {
        zustand = S3AN;
        prevMillis = aktMillis;
        Serial.println("Sprenger3 an");
      }
      break;
    case S3AN:
      if (aktMillis - prevMillis >= intervall) {
        zustand = S2AUS;
        Serial.println("Sprenger2 aus");
      }
      break;
    case S2AUS:
      if (weiter) {
        zustand = WARTEN;
        Serial.println("Sprenger3 aus");
      }
      break;
  }
}

Da Du nicht Deinen ganzen Sketch hier gezeigt hast, habe ich den Zeitalarm durch die Eingabe eines beliebigen Zeichens im seriellen Monitor simuliert. Dir geht es ja um das automatische Weiterschalten nach drei Sekunden. Ausgabe:

Sprenger1 an
Sprenger2 an
Sprenger1 aus
Sprenger3 an
Sprenger2 aus
Sprenger3 aus

Danke!

Das sieht interessant aus. Muß ich mal testen...