Pages: [1]   Go Down
Author Topic: reset des millis() Wertes  (Read 1843 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nach einigen (mehr oder weniger) sinnvollen Kommentaren, will ich nun auch mal eine Frage in die Runde werfen.

Es geht um den Null-Durchlauf des "millis()" Wertes. Da ich in einem Projekt mit einem Unix Timestamp arbeite, kann ich recht einfach mit dem Wert den millis() liefert rechnen. In regelmäßigen Abständen (vermutlich einmal pro Tag) wird der aktuelle Timestamp per NTP geholt. Dabei will ich dann den Wert für millis() auch gleich auf Null setzen, damit mir nicht der unweigerlich irgendwann auftretende Nulldruchlauf mitten am Tag die Zeitrechnung durcheinander bringt.

Den Wert selbst, sowie die Funktion habe ich in der Datei "wiring.c" gefunden :
Code:
volatile unsigned long timer0_millis = 0

unsigned long millis()
{
        unsigned long m;
        uint8_t oldSREG = SREG;

        // disable interrupts while we read timer0_millis or we might get an
        // inconsistent value (e.g. in the middle of a write to timer0_millis)
        cli();
        m = timer0_millis;
        SREG = oldSREG;

        return m;
}
Somit sollte eine Funktion

Code:
void resetmillis()
{
        uint8_t oldSREG = SREG;

        // disable interrupts while we read timer0_millis or we might get an
        // inconsistent value (e.g. in the middle of a write to timer0_millis)
        cli();
        timer0_millis =0;
        SREG = oldSREG;
}

kein Problem sein. Ein kurzes "find libraries -type f -exec grep 'millis() {} \; -print" liefert mir alle Stellen in den Libs, die auch mit dieser Funktion arbeiten. Das scheint aber nur in irgendwelchen Funktionen der Fall zu sein, daher denke ich, das ich auf der sicheren Seite bin, wenn ich den Wert von Hand auf 0 setze. (Zumal das ja irgendwann eh passiert)

Trotzdem die Frage, ob ich etwas übersehe? Fällt jemanden etwas ein, was mir auf die Füße fallen könnte?

Grüße,
Mario.
Logged

Forum Moderator
BZ (I)
Online Online
Brattain Member
*****
Karma: 266
Posts: 21673
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Meines Wissens kann man Millis() nicht zurücksetzen;
Ungeachtet dem fehlt mir in Deinem Kode das sei() um interrupts wieder zuzulassen.
Ist es notwendig micros() auch resettieren?
Grüße Uwe
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich vermute das der Aufruf "SREG = oldSREG;" durch das Setzen die Interrupts wieder erlaubt, denn die originale "millis()" Funktion macht auch kein "sei()" (siehe Code in wiring.c).
Die Variable  "volatile unsigned long timer0_millis" in der wiring.c ist halt auch nur eine ganz normale Variable, die ich somit innerhalb meines Programms auch setzen kann. In meinem Text habe ich nur "millis()" als Begriff verwendet, damit klar ist was ich meine.
Der Wert von micros() ist (soweit ich das beurteilen kann) unabhängig von millis(), daher muss der nicht genullt werden.
Logged

Forum Moderator
BZ (I)
Online Online
Brattain Member
*****
Karma: 266
Posts: 21673
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

"SREG = oldSREG;" ist eigentlich nur eine Zuweisung 2er Variablen und setzt kein sei().
Grüße Uwe
Logged

Munich/Germany
Offline Offline
God Member
*****
Karma: 11
Posts: 643
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Wozu millis() resetten?

Code:
vergangeneZeit = millis() - previousMillis;
Die Variablen müssen als unsigned long deklariert werden, Überlauf spielt dann keine Rolle.
Einzige Voraussetzung: previousMillis muss mindestens einmal innerhalb eines Überlaufs neu gesetzt werden.
Logged

_______
Manfred

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich denke nicht das SREG "nur" eine Variable ist. Ich vermute hier wird direkt ein Register angesprochen, genau wie bei den IO-Ports (PORTA, PORTB, etc...). Hier schreibt der AVR Compiler wohl beim Schlüsselwort "SREG" direkt auf das Register.
Zumindest werden bei der originalen millis() Funktion auch per cli() auch die Interrupts abgeschaltet und danach nicht per sei() wieder an, sondern durch schreiben des alten Registerwertes wieder aktiviert.

Laut http://www.cse.unsw.edu.au/~cs1721/05s2/lectures/slide48.html ist im Statusregister (SREG) auf das Interrupt enable/disable Bit (Bit 7) enthalten, damit werden also durch zurückschreiben des originalen Wertes (vor dem Ausschalten der Interrupts) in das Register auch die Interrupts wieder aktiviert.

Siehe auch http://www.mikrocontroller.net/articles/AVR-Tutorial:_Interrupts
Da wir in C arbeiten und unsere ISRs in der Regel Funktionen sind, brauchen wir uns um das Sichern der Register nicht zu kümmern, das wird in der Regel automatisch beim Sprung in eine Subroutine (in unserem Fall die ISR) gemacht. Dafür sorgt der Compiler. Trotzdem sollte man sich das merken, denn evtl. ist die ISR ja doch mal bei inline Assembler.
Mario.
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@MaFu: Du hast recht, allerdings hilft mir das bei meinem konkreten Problem nicht.

Einmal am Tag wird per NTP der aktuelle Zeitstempel geholt (unsigned long basetime) und der dabei aktuelle Wert von millis() (unsigned long uptime) gesichert.
Jede Minute wird nun eine Aktion ausgeführt, bei der der aktuell Timestamp mittels
Code:
unsigned timestamp  = ( millis() - uptime) / 1000 + basetime;
berechnet wird.
Wenn nun während des Tages der Nulldurchlauf stattfindet, liefert (millis() - uptime) einen negativen Wert, bzw. weil unsigned einfach nur Blödsinn. Und zwar solange, bis das nächste Mal die NTP-Routine den Wert für "uptime" übernimmt. Dann hab ich wieder (ich glaub 53,x Tage) Ruhe.
Genau das will ich vermeiden, indem ich den Wert auf 0 setze.

Natürlich kann ich auch prüfen, ob millis() < uptime ist, aber dann muss ich etvl. zu einer "ungünstigen" Zeit in die NTP-Routine verzweigen. Dann lieber zu einem definierten Zeitpunkt dafür sorgen das am nächsten Tag (oder auch die folgenden Tage, falls mal Netzwerk nicht geht) kein Blödsinn passiert.
Mario.
Logged

Munich/Germany
Offline Offline
God Member
*****
Karma: 11
Posts: 643
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Doch, das hilft Dir schon.
Dein
Code:
(millis() - uptime)
entspricht ja meinem
Code:
millis() - previousMillis
. Und da ja wegen "unsigned long" keine negativen Werte entstehen passt es auch trotz Überlauf.

Beispiel:
Gehen wir mal davon aus, dass der aktuelle millis Wert 4294967290 entspricht (also kurz vor dem Überlauf).
Sagen wir weiterhin, uptime wurde kurz vorher gesetzt und steht auf 4294967280.

Dann zählen wir millis mal hoch und prüfen das Ergebnis beim Überlauf (Ergebnis = millis() - uptime):
4294967290 - 4294967280 = 10
4294967291 - 4294967280 = 11
4294967292 - 4294967280 = 12
4294967293 - 4294967280 = 13
4294967294 - 4294967280 = 14
4294967295 - 4294967280 = 15 (jetzt kommt der Überlauf)
         0 - 4294967280 = 16
         1 - 4294967280 = 17
         2 - 4294967280 = 18
         3 - 4294967280 = 19


Wie Du siehst, passiert kein "Blödsinn".
« Last Edit: January 04, 2012, 08:28:51 am by MaFu » Logged

_______
Manfred

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, das überzeugt mich. Dann habe ich also eine Lösung für ein Problem entwickelt, das es gar nicht gibt. :-)
Ich hatte mich schon gewundert, warum keine sonst dieses Problem zu haben schien. Google hatte nix wirklich sinnvolles gefunden, obwohl ein Haufen Sketche und Libs fleissig mit den Differenzen arbeiten.

Danke nochmal fürs Vorrechnen.
Logged

Offline Offline
God Member
*****
Karma: 11
Posts: 599
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wieso ergibt "0 - 4294967280" die Zahl 16?

Gruß Chris
Logged


Germany
Offline Offline
Edison Member
*
Karma: 47
Posts: 2322
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Weil du mit nichtvorzeichenbehafteten Long-Varablen nur von 0 bis 4.294.967.295 zählen kannst. Dis Subtraktion ist etwas schwerer zu überblicken, also rechnen wir einfach mal mit der Umkehrrechenoperation und Addieren zu der 16 einfach 4.294.967.280. Der Taschenrechner spuckt 4.294.967.296 aus, liegt also auf dem nächsten Zahlenwert nach der letzten zulässigen Zahl: Zack, Überlauf, 0. smiley-grin
Logged

Mein Arduino-Blog: http://www.sth77.de/ - letzte Einträge: Teensy 3.0 - Teensyduino unter Window 7 - Teensyduino unter Windows 8

Pages: [1]   Go Up
Jump to: