Überlaufsicheren Timer - etwas alle x Sekunden machen

Hi zusammen,

in Anlehnung an einen anderen Beitrag von mir hab ich nun mal versucht, mich mit dem Thema Überlaufsicherer Timer auseinanderzusetzen.

Beispiel:
Ich möchte, dass alle 20 Sekunden ein Alarm geschlagen wird (in dem Fall einfach nur die Ausgabe des Wortes Beep). Der Alarm soll jeweils 10 Sekunden dauern.

Bin ich mit diesem Sketch "Überlaufsicher", d.h. läuft die Schleife auch bei einem Überlauf von millis() sauber durch?

bool AlarmStartSet=false;
unsigned long AlarmAbgelaufen=0;
unsigned long DauerBisRepeat=20000;
unsigned long AlarmStart=0;
unsigned long AlarmDauer=10000;

void setup() {
  Serial.begin(115200);
}

void loop() {
  if (millis() - AlarmAbgelaufen > DauerBisRepeat) {
    // Startzeitpunkt des Buzzers setzen
    if (AlarmStartSet == false) {
      // Der Startzeitpunkt des Alarms ist noch nicht gesetzt -> also machen wir das jetzt
      AlarmStart = millis();
      AlarmStartSet = true;
    }

    if (millis()-AlarmStart < AlarmDauer) {
      // Die Alarmzeit ist noch nicht abgelaufen, also Beepen!
      Serial.print("Beep  ");
      delay(1000);
    } else {
      Serial.println("Alarm abgelaufen!");
      // Zeitpunkt setzen, wann der Alarm abgelaufen ist
      // Brauchen wir, damit klar ist, wann die nächste Alarm-Wiederholung einsetzt
      AlarmAbgelaufen = millis();
      AlarmStartSet = false;
    }
  } 
}

Bitte sagt ja;-)
Dann hab ichs begriffen und freu mich.

LG Daniel

Und wozu das delay(1000); im Code?

Dass ich zwischen jedem Piepser 1 Sekunde Pause hab :wink:
Aber passt der Rest so? Ist das "Überlaufsicher"?

naja, du pausierst mit dem delay() deinen code immer für eine Sekunde. Deine Vergleiche mit millis() kommen so ins stocken. Den "BEEP" Output kannst du ja auch über millis() steuern.

Ja der Code ist Überlaufsicher. (Aber etwas umständlich gelöst)

Puh, ok, dann hab ich ja schon mal ein kleines Erfolgserlebnis.

Wenn du großen Bock hast, mir eine Verbesserung zu geben, würde mich das freuen.
Ich lerne ja immer gerne was dazu.

Aber ich will dich hier auf keinen Fall beschäftigen und den Eindruck erwecken, dass ich meinen Grips nicht selber anstrengen will, also nur wenn du Bock hast.

Ansonsten schon mal Danke für deine Rückmeldung.

Ah - da war ja was... da steht ja noch ein ignore drin.

bool tik, tak  = false;
unsigned long lastmillis = 0;
unsigned long mehrlastmillis = 0;
const unsigned long allePaarSekunden = 2000;
const unsigned long alleHalbeSekunde = 500;

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));;
}

void loop()
{
  if (millis() - lastmillis >= allePaarSekunden)
  {
    lastmillis = millis();
    tik = !tik;
    Serial.print(F("TIK ="));
    Serial.println(tik);
  }
  if (millis() - mehrlastmillis >= alleHalbeSekunde)
  {
    mehrlastmillis = millis();
    tak = !tak;
    Serial.print(F("TAK ="));
    Serial.println(tak);
  }
}

Weil ich heute ein guter bin

1 Like

:blush: :hugs:

Danke dir!

image

Dann noch in fast richtig

bool tik, tak  = false;
void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));;
}

void loop()
{
  ausgabeTik();
  ausgabeTak();
}

void ausgabeTik()
{
  const unsigned long pause = 500;
  static unsigned long lastmillis = 0;
  if (millis() - lastmillis >= pause)
  {
    lastmillis = millis();
    tik = !tik;
    Serial.print(F("TIK ="));
    Serial.println(tik);
  }
}

void ausgabeTak()
{
  const unsigned long pause = 2000;
  static unsigned long lastmillis = 0;
  if (millis() - lastmillis >= pause)
  {
    lastmillis = millis();
    tak = !tak;
    Serial.print(F("TAK ="));
    Serial.println(tak);
  }
}

prost! Ich bin Flaschenkind. Kannst ja mal schaun, was sich geändert hat und warum diese Version die Bessere ist.

Ich auch...heute gibts ein Augustiner Edelstoff!

Mach ich. Ich hoff ich begreifs :wink:
Dankeschön

Ich hatte mich jetzt auch bemüht, wenn auch nicht so elegant wie von my_xy_projekt

bool alarm = false;
unsigned long millisMerker;
unsigned long beepMillisMerker;
unsigned long beepInterval=1000;
unsigned long dauerBisRepeat=20000;
unsigned long alarmDauer=10000;

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
}

void loop() {
  if (millis() - millisMerker > dauerBisRepeat && !alarm) {
    alarm = true; Serial.println("Alarm!");
    millisMerker = millis();
  }
  if (millis() - millisMerker > alarmDauer && alarm) {
    alarm = false; Serial.println("Alarm abgelaufen!");
    millisMerker = millis();
  }
  if (millis() - beepMillisMerker > beepInterval && alarm){
    Serial.println("Beep   ");
    beepMillisMerker = millis();
  }
}

der TO ist bei mir noch in einer Liste... ich kenne sein Ausgangsproblem nicht.
.. Aber alles gut. Deine Lösung geht schon.

Danke auch dir @Plumps
Da war ich dann doch noch weit von der idealen Lösung entfernt.
Nun muss ich mir mal beide Lösungen anschauen und versuchen, zu verstehen.
Denn da haperts manchmal noch, ich denk einfach oft zu kompliziert...

Es geht auch kompliziert:


#include <CombieTimer.h>
#include <CombiePin.h>
#include <CombieTypeMangling.h>

using namespace Combie::Millis;


Combie::Pin::OutputPin<13>      horn;
Combie::Timer::Pulsator         puls   {20_sec}; // liefert alle 20000 ms einmal true sonst false
Combie::Timer::FallingEdgeTimer toff   {10_sec}; // abfallende Flanke wird verzoegert
 
void setup(void) 
{
  horn.init();
}

void loop(void) 
{
  horn = toff = puls;
}

CombieLib.zip (975 KB)

Ah, das ist quasi eine von dir geschriebene Bibliothek.
Puh, so weit wenn ich schon wäre.
Klingt auch sehr interessant, da hab ich jetzt ja einiges zum rumwursteln.

Ich beschäftige mich jetzt zwar auch schon eine ganze Weile mit dem Thema "Arduino" und C++ aber komm nur langsam voran ;-(

Was mir im Hirn immer Probleme bereitet ist dieses Schleifen-Prinzip, das man bei Mikrocontrollern hat, warum auch immer ich mich da so hart tue.
Aber wird schon noch werden...

Schön finde ich auch das Gespiele mit dem Modulo %. Es Spart eine Menge an unsigned Long Variablen.

uint16_t blinkerIntervall= 2000;   // An + Aus Zeit des Blinkers

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

void loop() {
  if ( millis() % blinkerIntervall*2 > blinkerIntervall) digitalWrite(LED_BUILTIN,HIGH);
  else digitalWrite(LED_BUILTIN,LOW);
}

Geht natürlich auch mit unterschiedlichen An und Aus Zeiten.

uint16_t blinkerIntervall = 2000;   // An + Aus Zeit des Blinkers
uint16_t blinkerAnZeit = 300;      // Zeit die die LED an ist. 

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

void loop() {
  if ( millis() % (blinkerIntervall+blinkerAnZeit) > blinkerIntervall) digitalWrite(LED_BUILTIN,HIGH);
  else digitalWrite(LED_BUILTIN,LOW);
}

Du machst mich fertig!

image

Ich merke mit jeder Antwort von euch immer mehr, dass ich nichts weiß!
Modulo % ... ok.... ich glaub ich meld morgen 8 Wochen Urlaub bei meinem Chef an und studiere mich in die Sache rein!

Hallo
Ich habe auch noch Einen :nerd_face:
Deine Aufgabenstellung kann man super für die Anwendung der OOP verwenden, ohne Class-Defintion, es geht auch ohne Extras!
Aber nun zum Eingemachten:
Der Sketch hat drei Timer-Objekte:

enum {Alarm, Blink, BlinkBlink}; // timer names

Diese Objekte werden über diese Methode abgefackelt:

bool checkTimer(TIMER &time_) {
  return ((currentTime - time_.stamp >= time_.duration && time_.control_) ? true : false);

Den Rest dazu findest Du im Sketch, der auf einem Arduino UNO getestet worden ist.

// BLOCK COMMENT
// https://www.learncpp.com/cpp-tutorial/
// https://forum.arduino.cc/t/uberlaufsicheren-timer-etwas-alle-x-sekunden-machen/903257
#define ProjectName "Überlaufsicheren Timer - etwas alle x Sekunden machen"
// CONSTANT DEFINITION
// you may need to change these constants to your needs
constexpr unsigned long AlarmTime {20000};
constexpr unsigned long BlinkTime {10000};
constexpr unsigned long BlinkBlinkTime {1000};

// VARIABLE DECLARATION AND DEFINTION
enum {Alarm, Blink, BlinkBlink}; // timer names
unsigned long currentTime;
struct TIMER {
  int name_;
  unsigned long duration;
  bool control_;
  unsigned long stamp;
};
TIMER alarms [] {
  {Alarm, AlarmTime,  true,  0},
  {Blink, BlinkTime, false,  0},
  {BlinkBlink, BlinkBlinkTime, false,  0},
};
// FUNCTIONs
bool checkTimer(TIMER &time_) {
  return ((currentTime - time_.stamp >= time_.duration && time_.control_) ? true : false);
}
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);
   alarms[Alarm].stamp = alarms[Alarm].duration; // start condition 
}
void loop () {
  currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);
  for (auto &alarm : alarms) {
    if (checkTimer(alarm)) {
      switch (alarm.name_) {
        case Alarm:
          alarms[Alarm].control_ = false;
          alarms[Blink].stamp = currentTime;
          alarms[Blink].control_ = true;
          alarms[BlinkBlink].control_ = true;
          Serial.println(F("start beep"));
          break;
        case Blink:
          alarms[Alarm].stamp = currentTime;
          alarms[Alarm].control_ = true;
          alarms[Blink].control_ = false;
          alarms[BlinkBlink].control_ = false;
          Serial.println(F("\nstopp beep"));
          break;
        case BlinkBlink:
          alarms[BlinkBlink].stamp = currentTime;
          Serial.print(F("Beep"));
          break;
      }
    }
  }
}

Viel Spass beim Studium der Möglichkeiten, die die OOP bietet.

Uppss dan haben wir im Forum einen weniger, den wie wilste Schreiben ohne Kopf, und ohne Kopf rumlaufen ist auch ziemlich dämlich :joy:

:laughing:Da hast wahrscheinlich Recht...

Meistens:
Es ist das "Denken in Nebenläufigkeiten" was genau solange unmöglich ist, bis der Groschen fällt.