Millis() auf einen Startwert setzen, um Overflow zu testen

Heute mal wieder eine etwas andere millis()-Frage:

Ich möchte ein Nano-Projekt testen, was bei einem Überlauf passiert und ob alles glatt läuft oder sich der Nano aufhängt.

Dazu könnte ich ja schnell mal mehrere Wochen das Projekt laufen lassen und dann schauen, ob sich die Kiste aufhängt. Dauert mir aber zu lange :face_with_raised_eyebrow::bangbang:

Für Testzwecke möchte ich die millis() einfach mal vorstellen, um die Wartezeit zu verkürzen.

Welche Register müsste ich hier wie verdrehen?

Versuche dies

extern volatile unsigned long timer0_millis ;

void setup() {
  Serial.begin(115200); Serial.println();
  noInterrupts();
  timer0_millis = 0xFFFFFFFF - 10000; 
  interrupts();
}

void loop() {
  Serial.println(millis());
  delay(1000);
}
1 Like

Ich habe sowas schon mal gemacht, weiß aber nicht mehr wie genau. AFAIR liest millis() nur eine globale Variable, die per Code geändert werden kann.

Danke, die war's wohl:

1 Like

Die Register habe ich noch mitgespeichert - gerade hier gemacht.... :wink:

1 Like

Hier habe ich auch noch etwas gefunden:

Probiere ich später mal aus.

1 Like

Ach schau - der ist ja von mir :slight_smile: Danke fürs finden. Und +1 fürs suchen!

Da sieht man was für Murks passieren kann wenn Code nicht in Code Tags </> gesetzt wird.

Hallo,
oder Du nimmst die micros() Funktion die läuft nach ~70 Minuten über.

Der Code ist in Tags.
Schau das Original.

Muss man das Statusregister sreg vorher sichern und anschließend wieder zurückholen? Schaden tutˋs sicher nicht, oder?

Kenne das von PIC-Assembler, da sollte man das wreg, pclath, fsr0 etc. ebenfalls wegsichern …

Ich mach es in jedem Fall.
Wenn Du das sicherst und zurück schreibst, kann auf sei() verzichtet werden.

Nein. Warum wollen Sie es speichern?
micros() erledigen die meiste Arbeit.

Damit Interrupts abgeschaltet bleiben wenn sie es vorher schon waren.

ah klar, aber in einem typischen Sketch sind sie immer aktiviert (so funktioniert millis() ...)

Nein, es schadet nicht.
Ist aber auch nicht immer nötig.

Ich mache sowas meist so:

#include "util/atomic.h" 
#define CriticalSection ATOMIC_BLOCK(ATOMIC_RESTORESTATE)

extern volatile unsigned long timer0_millis;

void setup() {
  Serial.begin(9600); 
  Serial.println();

  CriticalSection
  {
    timer0_millis = 0xFFFFFFFF - 10000; 
  }

  // oder als Einzeiler:
  CriticalSection timer0_millis = 0xFFFFFFFF - 10000; 

}

void loop() {
  Serial.println(millis());
  delay(1000);
}

Das hat den Vorteil, dass es eigentlich immer das gewünschte tut.
Auch wenn man den Code transportiert, z.B. aus ISR heraus aufruft.

vergiss das.
Wenn du "millis" verändern würdest, hast du EINEN neuen Testfall abgedeckt
Fehler können - wenn man sich nicht genau an Blink Without Delay hält - aber auch zu jedem anderen Millisstand auftreten.

"millis" Rollover kann man gut mit einer Byte Variable beweisen dass es kein Problem ist.

echt testen kannst du nur mit echten millis und 49 Tage lang beobachten ob Fehler auftreten.

Googeln wird dir helfen um Sicherheit zu bekommen: wenn deine if's richtig sind, ist der Rollover kein Problem.

Das ist deutlich schwieriger/problematischer, als man auf den ersten Blick meinen mag.
Beispiel:

byte a = 1;
byte b = 44;

if(a-b < 0) Serial.println(F("a-b") );
if(b-a < 0) Serial.println(F("b-a") );

Ausgabe: a-b

das ist ein anderes Problem als Rollover (aber immer unsigned math)

if(a < b) Serial.println(F("a-b") ); else Serial.println(F("b-a") );

Die if-Abfragen sind schon so gestrickt, dass es passen sollte, z.B.

    if ((millis() - millis_antenne_alt > 500))      // alle halbe Sekunde die Antenne ein-/ausschalten (= Zeichen, dass Aktualisierung möglich ist)
    {
        millis_antenne_alt = millis();

Wenn ich das Setzen des timers gleich zu Beginn in setup() einbaue, wird der Sketch erst einmal gebremst (keine Ahnung warum), dann läuft er aber los und die millis() laufen auch brav über.

Mein Sketch tut weiterhin was er soll.

Das passt auch!

Verstehe ich nicht.

(a-b < 0) ist genau so ein Ausdruck, wie auch beim "Blink Without Delay" verwendet wird.
Wenn man das mit byte veranstaltet, und darum drehte es sich ja, dann beweist mein Beispiel, dass der Unterlauf bei der Subtraktion eben NICHT den Überlauf kompensiert.
Das "Blink Without Delay" Prinzip ist somit nicht so einfach auf byte als Datentype übertragbar.

Erst ein Cast byte(a-b) würde die Situation retten
if(byte(b-a) < 0) Serial.println(F("b-a") );

warning: comparison is always false due to limited range of data type [-Wtype-limits]

Ich weiß, bei "Blink Without Delay" wird meist > oder >= verwendet. Aber das würde das Problem nicht so deutlich in den Vordergrund drücken.

Teste mal, nur so zum Spass:

  byte a = 200;
  byte b = 200;

if(a+b >= 300) Serial.println(F("Aua!") );