millis() überlauf umgehen?

Hallo,

da der ja bekannterweiße millis iwann voll ist dachte ich mir ich setze einfach auf second(); von der time lib welche per DCF77 gefüttert wird?

ich müsste das dann etwas anders gestalten aber sind aufgaben welche ca nur alle 30 sekunden mal ausgeführt werden sollen.

oder läuft in der time lib auch iwann mal was über?

im grunde so aufgebaut

#include 
#include 

#define DCF_PIN 23
#define DCF_INTERRUPT 23

time_t time;

  DCF.Start();
  setSyncInterval(30);
  setSyncProvider(DCF.getTime);

time_t DCFtime = DCF.getTime(); // Check if new DCF77 time is available
  if (DCFtime!=0)
  {
    Serial.println("Time is updated");
    setTime(DCFtime);
  }

sind aufgaben welche ca nur alle 30 sekunden mal ausgeführt werden sollen.

Dann spielt der millis() Überlauf doch gar keine Rolle....

Bleibt da der Controller nicht hängen? Dann tut der Doch Garnichts mehr...

Nee, der fängt einfach bei Null von vorne an. :)

Nö, der Wert fängt wieder bei 0 an.

Achso :D verbinde overflow immer noch mit sicherheitslücken und exploits und da startet das Betriebssystem oder das Programm in der Regel nicht einfach mal neu ohne etwas ungewolltes noch zu tun

Counter Overflows sind ganz normal. Sie stellen kein Problem dar, wenn man sie kennt und korrekt abhandelt.

Also wird das Programm im schlimmsten Fall einen Durchlauf auslassen.

Nein! Besorge dir mal Lektüre, oder google im Internet.

Die Thematik wird 1000fach angesprochen.

Wenn ich von einem Wert x (hier ausgehend von einem Byte) einen Wert y abziehe, der größer x ist, geschieht folgendes

x = 10; y = 11;

x = x - y; x hat nun den Wert 255. Eigentlich würde man jetzt sagen, das Ergebnis müsste -1 sein. Da es sich aber bei einem byte oder unsigned long um einen Wertebereich aus positiven Zahlen (ohne Vorzeichen handelt), stellt der Wert -1 den höchst möglichen Wert von dem Werteberech da. (2^8)-1 ergbit 255. Somit kümmert dich der Werteüberlauf nicht, solange beim unsigned long du keine Wartezeiten von irgendwas um die 40 Tage hast.

mpl1337: Also wird das Programm im schlimmsten Fall einen Durchlauf auslassen.

Nein! Bei korrekter Abhandlung nicht.....

Hier mal ein Beispiel aus meiner Wühlkiste, ein Blinker welcher ohne Unterlass blinkt. Wird ein exakter Zeitpunkt verpasst, wird dieses aufgeholt.

class TimerTick
{
  private:
  unsigned long lastHit;
  unsigned long interval;
  
  public:
  TimerTick(unsigned long interval):interval(interval){}
  
  bool abgelaufen()
  {
    if(millis() - lastHit >= interval)
    {
        lastHit += interval; // mit aufholjagt
        return true;  
    }
    return false;
  }  
};

const byte led = 13;
TimerTick timer(500); // alle 0,5 sec


void tuwas()
{
    digitalWrite(led,!digitalRead(led)); // toggle LED
}

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

void loop() 
{
  if(timer.abgelaufen()) tuwas();   
}

Ich mach auch immer:

if (millis() - letzterZeitpunkt >= zeitdauer)

Funktioniert astrein.

Gruß Chris

Genau!

Eine kleine Zusammenfassung: :) millis() zählt die Millisekunden seit Prozessorstart. Es ist eine Variable vom Typ unsigned long und kann deshalb von 0 bis 4294967295 zählen. Das bedeutet dass sie nach "fast 50 Tagen" (wie es im Arduino-Manual heißt) überläuft, um genau zu sein nach 49,71 Tagen (49 Tage, 17 Stunden, ...).

Häufig wird millis() zum messen von Zeitintervallen verwendet (dafür ist es ja auch gedacht). Wenn man also Rechenoperationen mit millis() durchführt kann der Überlauf ein Problem sein, aber nur wenn man es falsch macht.

Richtig macht man es so:

  • unsigned long für Zeitvariable verwenden (und nicht long oder int)
  • einen Startzeitpunkt festhalten
  • den Startzeitpunkt von der aktuellen Zeit subtrahieren um auf die Differenz zu kommen
  • überprüfen ob diese Differenz größer ist als das gewünschte Intervall

z.B.: Intervall ist 5 Sekunden (5000 millis)

unsigned long startTime = millis();
unsigned long interval  = 5000;

...

if ( millis() - startTime >= interval )
{
    // mach was
}

So wird selbst bei einem Überlauf von millis richtig gezählt.

Super, vielen Dank. Habt mir echt geholfen :) dann kann ich mich jetzt dran machen alle Waits raus zu hauen :)

uxomm:

unsigned long interval  = 5000;

Hätte man das nicht per Integer lösen können?

Gruß Chris

Wenn Du an const int interval = 5000; denkst, dann sicherlich. Bei einer Variablen kommt es aber darauf an, was Du im Programm so vorhast ;)

Ich mach auch immer:

Code: [Select]

if (millis() - letzterZeitpunkt >= zeitdauer)

Funktioniert astrein.

Gruß Chris

was passiert, wenn letzterZeitpunkt kurz vorm Überlauf und die if Abfrage kurz nach dem Überlauf liegt?

was passiert, wenn letzterZeitpunkt kurz vorm Überlauf und die if Abfrage kurz nach dem Überlauf liegt?

Es funktioniert trotzdem:

Um es anschaulicher zu machen, nehmen wir an, dass alle Variable "nur" Byte (uint8_t) seien, also nur Werte zwischen 0 und 255 annehmen können.

z.B. zeitdauer = 20 letzterZeitpunkt = 250 millis() = 3

if (millis() - letzterZeitpunkt >= zeitdauer)

wir rechnen (mit Überlauf) 3 - 250 = 9 also false