Funktionen blockieren weiteres Programm (Kein delay())

Hallo zusammen,
ich habe ein Problem mit dem unteren Code.
Was passieren soll: Alle 20 Sekunden soll eine LED an Pin 4 für 10sek blinken und ein passive buzzer einen Sirenenton für 5sek ausgeben. Die LED und der Ton sollen "gleichzeitig" starten. 10sek nach dem Ende des blinkens bzw. 15sek nach dem letzten Ton soll das wieder von vorne anfangen.
Was passiert: Die LED blinkt und der Ton wird ausgegeben, jedoch hintereiander. Erst wird der Ton für 5sek ausgegeben, anschließend blinkt die LED für 10sek. Und danach 20sek später wiederholt sich alles.

Die beiden Funktionen alarmtonAn() und alarmAn() scheinen die Ausführung des weiteren Programms zu blockieren...

Habt Ihr eine Idee, wo der Fehler ist?

Ich habe es sowohl auf einem "Arduino" Uno von AZ-Delivery (Mikrocontroller Board AZ-ATmega328-Board mit USB-Kabel) als auch auf einem Nano probiert, bei beiden das selbe.
Im Internet habe ich auch nichts gefunden.

unsigned long divAlarmTime = millis();

void setup() {
  pinMode(4, OUTPUT);
  pinMode (5, OUTPUT);
}

void loop() {
  if (millis() - divAlarmTime > 20000) //alle 20sek soll die Funktion alarmtonAn() und alarmAn() "gleichzeitig" aufgerufen werden
  {
    alarmtonAn();
    alarmAn();
    divAlarmTime = millis();  //setzt den Timer zurück
  }
}

void alarmAn()
{
  unsigned long previousMillis = millis();
  int ledState = LOW;
  unsigned long previousMillisBlink = millis();
  while (millis() - previousMillis < 10000)
  {

    if (millis() - previousMillisBlink > 400)
    {
      if (ledState == LOW)
      {
        ledState = HIGH;
      }
      else
      {
        ledState = LOW;
      }
      digitalWrite (4, ledState);
      previousMillisBlink = millis();
    }

  }
  digitalWrite (4, LOW);
  previousMillisBlink = millis();
}

void alarmtonAn()
{
  unsigned long previousMillisTon = millis();
  unsigned long previousMillisTonDauer = millis();
  int i = 700;
  while (millis() - previousMillisTonDauer < 5000)  //für 5sek wird der Ton ausgegeben
  {
    while (i < 800) //Der Ton wechselt von der Frequenz von 800Hz Schritt für Schritt zu 700Hz und wieder zurück
    {
      if (millis() - previousMillisTon > 3)//Ton wird für 3millisekunden ausgegeben, bevor der Ton 1Hz höher oder niedriger wird
      {
        tone(5, i);
        i++;
        previousMillisTon = millis();
      }
    }
    while (i > 700)
    {
      if (millis() - previousMillisTon > 3)
      {
        tone(5, i);
        i--;
        previousMillisTon = millis();
      }
    }
    noTone (5);
  }
}

Wirkt wie ein delay()

2 Likes

Vielleicht.
kompiliert. mehr auch nicht.
Wenns nicht funktioniert, ist irgendeine Taste hier kaputt :wink:

constexpr uint32_t beeperTime {5UL * 1000};
constexpr uint32_t blinkTime {15UL * 1000};
uint32_t alarmStart;
uint32_t myMillis;

constexpr byte beeperPin {4};
constexpr byte ledPin {5};

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(beeperPin, OUTPUT);
  pinMode (ledPin, OUTPUT);
}

void loop()
{
  myMillis = millis();
  if (myMillis - alarmStart > blinkTime)
  { alarmStart = myMillis; }
  beeper();
  flashLight();
}
//
void beeper()
{
  constexpr uint16_t startTone {700};
  constexpr uint16_t endTone {800};
  static uint16_t myTone = startTone;
  static bool aufAb = (myTone == startTone);
  static uint32_t lastSwitchTime = 0;
  constexpr uint32_t intervall {3};
  if (myMillis - alarmStart < beeperTime)
  {
    // Frequenzgrenzen:
    if (myTone > endTone)
    { aufAb = LOW; }
    else if (myTone < startTone)
    { aufAb = HIGH; }
    // Frequenzeinstellung:
    if (myMillis - lastSwitchTime > intervall)
    {
      lastSwitchTime += intervall;
      aufAb == HIGH ?  myTone++ : myTone--;
    }
    // Ausgabe
    tone(beeperPin, myTone);
  }
  else
  {
    noTone(beeperPin);
    myTone = startTone;
  }
}
//
void flashLight()
{
  static uint32_t lastSwitchTime = 0;
  constexpr uint32_t intervall {250};
  if (myMillis - alarmStart < blinkTime)
  {
    if (myMillis - lastSwitchTime > intervall)
    { digitalWrite(ledPin, !digitalRead(ledPin)); }
  }
  else
  { digitalWrite(ledPin, LOW); }
}
1 Like

"Warte 10 Sekunden"
oder
"Solange 10 Sekunden nicht vorbei sind"
haben den geleichen Effekt.

1 Like

Mit allgemeineren Begriffen und längerem Suchen hättest du was gefunden
Du möchtest ganz schön viel. Deshalb ist das auch ein mittellanges Programm

Einmal (fast) der ganze Code in function loop() reingeklatscht:

// Du hast  alles in allem 5 Timer
// 20 Sekunden alles von vorne
// 10 Sekunden LED blinken
//  5 Sekunden Sirene an

// LED An / Aus    0,5 Sekunden
// Sirene An / Aus 1,0 Sekunden

const byte    LED_pin    = 4;
const byte    Buzzer_pin = 5;

// 20 Sekunden-Timer
unsigned long Timer20Sec     = 0;
unsigned long MainInterval   = 20000;

// 10 Sekunden Timer = wie lange die LED blinken soll
unsigned long Led_BlinkTimer    = 0;
unsigned long LedBlinkInterval  = 10000;

// 0,5 Sekunden Timer für LED an/aus
unsigned long Led_OnOffTimer    = 0;
unsigned long Led_OnOffInterval = 500;

// 5 Sekunden-Timer wie lange die Sirene eingeschaltet sein soll
unsigned long Buzzer_Timer      = 0;
unsigned long BuzzerOnInterval  = 5000;

// 1 Sekunden Timer Sirene An/Aus
unsigned long Buzzer_OnOffTimer    = 0;
unsigned long Buzzer_OnOffInterval = 1000;


boolean buzzerOn  = false; // "Schalter" Blinken an/aus
boolean blink_LED = false; // "Schalter" Sirene  an/aus

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");  
  digitalWrite(LED_pin, LOW);
  digitalWrite(Buzzer_pin, LOW);
  pinMode(LED_pin,    OUTPUT);
  pinMode(Buzzer_pin, OUTPUT);
  Timer20Sec = millis();
}


void loop() { // loop macht unendlich loopings
  // loop START START START START START START START

  
  // prüfe ob ein 20-Sekunden-Intervall vorbei ist
  if ( TimePeriodIsOver(Timer20Sec, MainInterval) ) {
    // wenn WIRKLICH 20 Sekunden vorbei sind
    Led_BlinkTimer = millis(); // Timer auf aktuelle Zeit setzen
    Buzzer_Timer   = millis();
    blink_LED = true; // LED blinken einschalten
    buzzerOn  = true; // Sirene einschalten
  }

  // prüfe ob LED blinken eingeschaltet ist
  if (blink_LED == true) {
    // prüfe ob 0,5 Sekunden vorbei sind
    if ( TimePeriodIsOver(Led_OnOffTimer, Led_OnOffInterval) ) {
      // wenn WIRKLICH 0,5 Sekunden vorbei sind
      // invertiere den Schaltzustand des LED_pins
      digitalWrite(LED_pin, !digitalRead(LED_pin) ) ;
    }
  }

  // prüfe ob LED-Blinkzeit vorbei ist
  if ( TimePeriodIsOver(Led_BlinkTimer, LedBlinkInterval) ) {
    // wenn WIRKLICH LED-Blinkzeit vorbei ist
    blink_LED = false;         // blinken ausschalten
    digitalWrite(LED_pin,LOW); // LED ausschalten 
  }


  // prüfe ob Sirene eingeschaltet ist
  if (buzzerOn == true) {
    // prüfe ob Sirenen ein/aus-Intervall vorbei ist
    if ( TimePeriodIsOver(Buzzer_OnOffTimer, Buzzer_OnOffInterval) ) {
      // wenn WIRKLICH Sirenen ein/aus-Intervall vorbei ist      
      // invertieren den Schaltzustand von Buzzer_pin
      digitalWrite(Buzzer_pin, !digitalRead(Buzzer_pin) ) ;
    }    
  }

  // prüfe ob Sirenen-Einschaltzeit vorbei ist
  if ( TimePeriodIsOver(Buzzer_Timer, BuzzerOnInterval) ) {
    // wenn WIRKLCIH Sireneneinschaltzeit vorbei ist    
    buzzerOn = false;             // Sirene aus ausschalten
    digitalWrite(Buzzer_pin,LOW); // Sirenen-IO-pin ausschalten 
  }
  // springe hoch zu loop START START START START START START START
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

.
.
einmal in sinnvolle Teilabschnitte unterteilt strukturiert in functions

// Du hast  alles in allem 5 Timer
// 20 Sekunden alles von vorne
// 10 Sekunden LED blinken
//  5 Sekunden Sirene an

// LED An / Aus    0,5 Sekunden
// Sirene An / Aus 1,0 Sekunden

const byte    LED_pin    = 4;
const byte    Buzzer_pin = 5;

// 20 Sekunden-Timer
unsigned long Timer20Sec     = 0;
unsigned long MainInterval   = 20000;

// 10 Sekunden Timer = wie lange die LED blinken soll
unsigned long Led_BlinkTimer    = 0;
unsigned long LedBlinkInterval  = 10000;

// 0,5 Sekunden Timer für LED an/aus
unsigned long Led_OnOffTimer    = 0;
unsigned long Led_OnOffInterval = 500;

// 5 Sekunden-Timer wie lange die Sirene eingeschaltet sein soll
unsigned long Buzzer_Timer      = 0;
unsigned long BuzzerOnInterval  = 5000;

// 1 Sekunden Timer Sirene An/Aus
unsigned long Buzzer_OnOffTimer    = 0;
unsigned long Buzzer_OnOffInterval = 1000;


boolean buzzerOn  = false; // "Schalter" Blinken an/aus
boolean blink_LED = false; // "Schalter" Sirene  an/aus

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  digitalWrite(LED_pin, LOW);
  digitalWrite(Buzzer_pin, LOW);
  pinMode(LED_pin,    OUTPUT);
  pinMode(Buzzer_pin, OUTPUT);
  Timer20Sec = millis();
}


void loop() { // loop macht unendlich loopings
  // loop START START START START START START START

  // prüfe ob ein 20-Sekunden-Intervall vorbei ist
  if ( TimePeriodIsOver(Timer20Sec, MainInterval) ) {
    // wenn WIRKLICH 20 Sekunden vorbei sind
    Led_BlinkTimer = millis(); // Timer auf aktuelle Zeit setzen
    Buzzer_Timer   = millis();
    blink_LED = true; // LED blinken einschalten
    buzzerOn  = true; // Sirene einschalten
  }

  LED_Blinken_Managen();
  Sirene_Managen();
  // springe hoch zu loop START START START START START START START
}


void LED_Blinken_Managen() {
  // prüfe ob LED blinken eingeschaltet ist
  if (blink_LED == true) {
    Blinke_die_LED();
  }

  // prüfe ob LED-Blinkzeit vorbei ist
  if ( TimePeriodIsOver(Led_BlinkTimer, LedBlinkInterval) ) {
    // wenn WIRKLICH LED-Blinkzeit vorbei ist
    blink_LED = false;         // blinken ausschalten
    digitalWrite(LED_pin, LOW); // LED ausschalten
  }
}

void Blinke_die_LED() {
  // prüfe ob 0,5 Sekunden vorbei sind
  if ( TimePeriodIsOver(Led_OnOffTimer, Led_OnOffInterval) ) {
    // wenn WIRKLICH 0,5 Sekunden vorbei sind
    // invertiere den Schaltzustand des LED_pins
    digitalWrite(LED_pin, !digitalRead(LED_pin) ) ;
  }
}


void Sirene_Managen() {
  // prüfe ob Sirene eingeschaltet ist
  if (buzzerOn == true) {
    SireneAnAus();
  }

  // prüfe ob Sirenen-Einschaltzeit vorbei ist
  if ( TimePeriodIsOver(Buzzer_Timer, BuzzerOnInterval) ) {
    // wenn WIRKLCIH Sireneneinschaltzeit vorbei ist
    buzzerOn = false;              // Sirene aus ausschalten
    digitalWrite(Buzzer_pin, LOW); // Sirenen-IO-pin ausschalten
  }
}

void SireneAnAus() {
  // prüfe ob Sirenen ein/aus-Intervall vorbei ist
  if ( TimePeriodIsOver(Buzzer_OnOffTimer, Buzzer_OnOffInterval) ) {
    // wenn WIRKLICH Sirenen ein/aus-Intervall vorbei ist
    // invertiere den Schaltzustand von Buzzer_pin
    digitalWrite(Buzzer_pin, !digitalRead(Buzzer_pin) ) ;
  }
}

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long & startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

vgs

1 Like

Ich erkläre nicht-blockierendes Timing gerne mit "eine Tiefkühl-Pizza backen".

Das steht jetzt in einem eigenen Thread damit ich nicht doppelt anpassen/verbessern muss.

vgs

2 Likes

Vielen Dank für die zahlreichen Antworten. Ich werde mich in den nächsten Tagen mit den verschiedenen Tipps auseinandersetzen.

Du entäuscht mich. "Arduino Forum lesen" ist nicht dabei. :wink: :wink:

Unter usw. versteckt :wink:

ist korrigiert

:wink: :wink::wink: :wink:

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.