Forum: Mikrocontroller und Digitale Elektronik STM32, Verstrichene Zeit mittels SysTick ermitteln, wie Overflow/Rollover berücksichtigen?


von Alex -. (alex796)


Lesenswert?

Hi

Ich möchte gerne die verstrichene Zeit mittels SysTick ermitteln. 
Allerdings bin ich ein wenig verwirrt, wie ich einen Überlauf 
berücksichtige.

Wenn wir annehmen, dass SysTick von 0 bis 5 läuft und dann überläuft:
1
[0,1,2,3,4,5]
Und dann zwei Zeitpunkte annehmen:
1
uint32_t alteZeit = 3
2
uint32_t neueZeit = 1

Bin ich mit folgendem Programm auf dem richtigen Trichter? Wenn nein, 
wie könnte man es eleganter/besser lösen?
1
void SysTick_Handler(void)
2
{
3
  msTicks++;
4
}
5
6
uint32_t verstricheneZeit()
7
{
8
uint32_t alteZeit = 3; // SysTick->Val vor Überlauf
9
funktionsAufruf1();
10
funktionsAufruf2();
11
uint32_t neueZeit = 1; // SysTick-Val nach Überlauf
12
if(neueZeit > alteZeit){
13
uint32_t verstricheneZeit = neueZeit - alteZeit + msTicks*SysTimerPeriode;
14
return verstricheneZeit;
15
}
16
else
17
{
18
uint32_t verstricheneZeit = neueZeit + (5-alteZeit)+1; // 1 + (5-3) + 1 = 4 Cycles
19
return verstricheneZeit;
20
}
21
msTicks = 0;
22
}

Mein Bauchgefühl sagt mir, dass ein erfahrener Programmierer eine 
wesentlich elegantere Lösung auf Lager hat ;) :)

: Bearbeitet durch User
von Ich (Gast)


Lesenswert?

Einfach so eine Auflösung nehmen, daß der Überlauf erst in zig Jahren 
ist, oder du immer so abfragst, daß max 1 Überlauf stattfindet.

von Norbert (Gast)


Lesenswert?

Alex -. schrieb:
> Mein Bauchgefühl sagt mir, dass ein erfahrener Programmierer eine
> wesentlich elegantere Lösung auf Lager hat ;) :)

(neueZeit - alteZeit) MOD 5

von (prx) A. K. (prx)


Lesenswert?

Alex -. schrieb:
> Wenn wir annehmen, dass SysTick von 0 bis 5 läuft und dann überläuft:

... dann hat man übersehen, dass der SysTick runterzählt.

: Bearbeitet durch User
Beitrag #7048283 wurde vom Autor gelöscht.
von (prx) A. K. (prx)


Lesenswert?

Wenn du sowohl den Wert von SysTick als auch die Anzahl Interrupts 
kombinierst, gibt es eine kleine Gemeinheit namens Race Condition. Wenn 
zur Laufzeit der Funktion, in der man diese beiden Zählerwerte liest, 
der SysTick von 0 auf 0x00FFFFFF (oder einem anderen gesetzten 
Reload-Wert) springt, dann kann es passieren, dass die beiden 
Zählerwerte nicht zueinander gehören. Also beispielsweise der SysTick 
schon auf 0x00FFFFFF steht und eigentlich ein Interrupt ausgelöst wurde, 
den der gelesene msTick Wert aber noch nicht widerspiegelt. Oder 
umgekehrt.

: Bearbeitet durch User
von Alex -. (alex796)


Lesenswert?

(prx) A. K. schrieb im Beitrag #7048283:
> Die Sache oben ist dann doch etwas komplizierter, denn er hat zwei
> Zähler, die er kombiniert. Die Variable msTick zählt die Anzahl
> SysTick-Interrupts und dazu kommt noch der Wert des SysTick selbst.
Die Situation, dass ich zwei Zähler kombiniere, ist nicht zwingend. Ich 
dachte lediglich, es wäre klug :)
Ich könnte im Prinzip aber genauso gut folgenden Ansatz wählen:
Ich schrieb:
> Einfach so eine Auflösung nehmen, daß der Überlauf erst in zig Jahren
> ist, oder du immer so abfragst, daß max 1 Überlauf stattfindet.

Irgendwie dachte/denke ich jedoch, dass ich sicherlich nicht der erste 
bin, der in solch einer Situation stand. Wie wird sowas normalerweise 
gelöst?

Ich glaube, dass mein obiger Ansatz im Ursprungspost funktionieren 
könnte (bei steigendem Counter - hatte vergessen, dass SysTick herunter 
zählt). Ich finde aber, dass meine Lösung ein wenig kompliziert 
aussieht.

Mache ich es mir unnötig schwer?

von (prx) A. K. (prx)


Lesenswert?

Alex -. schrieb:
> Die Situation, dass ich zwei Zähler kombiniere, ist nicht zwingend. Ich
> dachte lediglich, es wäre klug :)

Es macht die Sache deutlich komplexer. Wenn du das nicht brauchst, ist 
es klüger, es bleiben zu lassen.

Ich verwende gerne einen permanent laufenden Takt mit z.B. 1 KHz oder 10 
KHz, der bei den Cortex M naheliegenderweise aus dem SysTick Interrupt 
kommt. Und für alle zeitabhängigen Aktivitäten, die nicht genauer als 
dieser Takt sein müssen, verwende ich nur den. Dann tut es die 
beschriebene MOD Variante. Die sich bei Typen ab sizeof(unsigned) ganz 
von selbst ergibt, da die Arithmetik vorzeichenloser Typen in C so 
definiert ist.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Alex -. schrieb:
> Ich glaube, dass mein obiger Ansatz im Ursprungspost funktionieren
> könnte

Mit Einrückung sieht C Code deutlich schöner aus.

von A.S. (Gast)


Lesenswert?

Wenn Du bei 1,2 oder 4 Byte überlaufen lässt, brauchst Du den Überlauf 
nicht berücksichtigen, solange Du zuerst die Differenz in gleicher 
Auflösung bildest.

Wenn Du Mal us, ms und s brauchst, nimm 3 parallele timer die atomar 
lesbar sind.

Bei 32 Bit signed sind ms mehr als 20 Tage. Programmier sauber und mach 
dann trotzdem nach 20 Tagen einen Reset.

2 Zähler mixen erfordert meist durch den notwendigen Lock mehr 
Ungenauigkeit und arbeit als einfach 2 verschiedener zu nehmen

von PittyJ (Gast)


Lesenswert?

Mein STM32 hat auch eine Real-Time Clock.
    __HAL_RCC_RTC_CLK_ENABLE();
    __HAL_RCC_RTC_ENABLE();

Warum kann man die nicht benutzen, wenn es mal länger dauert?

von Modulo (Gast)


Lesenswert?

Norbert schrieb:
> (neueZeit - alteZeit) MOD 5

... bei einem Zähler, der von 0 bis 5 zählt, ist das nicht wirklich 
zielführend.

von Norbert (Gast)


Lesenswert?

Modulo schrieb:
> Norbert schrieb:
>> (neueZeit - alteZeit) MOD 5
>
> ... bei einem Zähler, der von 0 bis 5 zählt, ist das nicht wirklich
> zielführend.

Da hat er Recht, muss natürlich MOD 6 heißen!

Immer diese Flüchtigkeitsfehler zu später Stunde, da habe ich kein 
Verständnis…

von A.S. (Gast)


Lesenswert?

Ah, und vergessen:

Alex -. schrieb:
> msTicks = 0;

Mache das niemals. Denk nicht Mal dran.

Mit (atomaren) free running countern fällt jede Sonderbehandlung weg. 
Kein if, kein zurücksetzen, kein Lock. Einfach (jetzt-alt) und fertig.

von Alex -. (alex796)


Lesenswert?

Vielen Dank euch allen. Ich werde das ganze mal sacken lassen und mich 
heute damit näher beschäftigen.

Gruß,

von W.S. (Gast)


Lesenswert?

Alex -. schrieb:
> Ich möchte gerne die verstrichene Zeit mittels SysTick ermitteln.
> Allerdings bin ich ein wenig verwirrt, wie ich einen Überlauf
> berücksichtige.
>
> Wenn wir annehmen, dass SysTick von 0 bis 5 läuft und dann überläuft:

Also mal ne ernste Frage: Zu welchem Zweck willst du die seit welchem 
Startzeitpunkt verstrichene Zeit wissen?

Normalerweise ist es so, daß man z.B. irgend einen Ablauf programmieren 
will und dazu nach einer bestimmten Verzögerung irgend ein Signal setzen 
muß, oder daß man eine Zeitbegrenzung setzen will, damit man nicht bei 
irgend einer Aktion festklebt und alles blockiert. Das führt regelmäßig 
dazu, daß man eine Systemuhr braucht, die nach einer bestimmten Zeit ein 
Signal abgibt (eben sowas wie ein 'event'), so daß man darauf reagieren 
kann und in der Zwischenzeit sich um etwas anderes kümmern kann.

Die gewünschte Zeitspanne gibt man vor und nach Verstreichen derselben 
klingelt es quasi. Da sehe ich keinen Grund, eine verstrichene Zeit zu 
ermitteln.

Und wieso denkst du an Überläufe? Eine Systemuhr kennt allenfalls den 
Überlauf, der um Mitternacht stattfindet, wenn das Datum weitergezählt 
wird und die Uhr wieder auf 0 gestellt wird. Zumeist wird man den 
Systick so programmieren, daß er alle 1 ms oder alle 10 ms überläuft und 
damit einen Interrupt für die Systemuhr liefert. Wie kommst du auf einen 
Zählbereich von 0..5 ?

Mir kommt das Ganze ziemlich wirr vor. Zumindest kann ich da noch kein 
tragfähiges System drin erkennen.

W.S.

von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> Also mal ne ernste Frage: Zu welchem Zweck willst du die seit welchem
> Startzeitpunkt verstrichene Zeit wissen?

Ein Beispiel bei mir: Sensordaten kriegen diesen durchlaufenden 
Tick-Counter als Alter ins Record geschrieben. Wenn zu alt, dann 
ungültig. Seine Methode, msTicks stets zurück zu setzen, ist dafür 
freilich ungünstig. Den durchlaufen lassen und die Differenz zu 
berechnen ist besser.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

W.S. schrieb:
> Wie kommst du auf einen Zählbereich von 0..5 ?
Wieviele Finger 🖐️ hat eine Hand?

Natürlich werden solche Überlegungen auf binärer Ebene einfacher, wenn 
man eine Zweierpotenz nimmt. Und ein uC ist halt nun ein binäres Ding.

Und zum Problem selber empfehle ich die Betrachtung der millis() 
Funktion aus der Arduino-Ecke und ihrer Anwendung. Dort wird einfach ein 
möglicher Überlauf durch geschickte Anwendung von Integer-Arithmetik der 
Überlauf "herausgerechnet".

von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> Und wieso denkst du an Überläufe?

Bei seiner Kombination zweier Timer sind die zu berücksichtigen, beim 
Hardware SysTick Counter. Nur ist dieser Ansatz i.d.R. unnötig 
kompliziert.

> Mir kommt das Ganze ziemlich wirr vor.

Er übt noch. Da ist das normal.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Ein Beispiel bei mir: Sensordaten kriegen diesen durchlaufenden
> Tick-Counter als Alter ins Record geschrieben. Wenn zu alt, dann
> ungültig.

Das heißt, du kannst die aktuelle Uhrzeit in deinen Record schreiben. 
Wer will, kann dann die Zeitspanne zwischen "jetzt" und der 
Record-Uhrzeit selber berechnen. Dazu braucht es ne Uhrzeit, die da 
normalerweise von selbst mit abfällt.

Lothar M. schrieb:
> Wieviele Finger 🖐️ hat eine Hand?

Und wieviele Hände hat ein Mikrocontroller?

(prx) A. K. schrieb:
> Er übt noch. Da ist das normal.

Deshalb hab ich ja auch nicht geschimpft. Also Nachdenken ist zuerst 
angesagt.

W.S.

von Stefan F. (Gast)


Lesenswert?

> Wenn wir annehmen, dass SysTick von 0 bis 5 läuft und dann überläuft

Wenn das so ist, hat schon vorher jemand großen Bockmist gebaut. Mit so 
einer Idee schießt man sich früher oder später ins eigene Knie. Und mit 
Sicherheit bereitet man seinen Nachfolgern, die das Projekt fortsetzen, 
unnötigen Frust.

-------------------------------------------
Herbert Frickelmann, gestorben am 11.12.2021
Wir liebten seine Grillkünste, aber seine Software treibt uns in den 
Wahnsinn. Möge er ruhen in Frieden und nicht wieder kommen.
-------------------------------------------

Normalerweise lässt man den Systick Counter durchlaufen. Zeitspannen 
ermittelt man mit der Subtraktion. Angenommen, der Systick Counter hat 
32 Bit und wird im ms Intervall hochgezählt, dann so:
1
uint32_t start=systick();
2
...
3
uint32_t elapsed_time_ms=systick()-start;

Oder für Warteschleifen:
1
uint32_t start=systick();
2
uint32_t wait_ms=1000;
3
4
while (systick()-start < wait_ms) {
5
   ...
6
}

Oder für Abbrüche bei Zeitüberschreitungen:
1
uint32_t start=systick();
2
uint32_t max_ms=1000;
3
4
while (waiting_for_response) {
5
   ...
6
   if (systick()-start > max_ms) {
7
       return ERROR_CODE_TIMEOUT;
8
   }
9
}

Der entscheidende Punkt ist die Subtraktion. Mit einer Addition 
funktioniert es bei Überlauf nicht.

von (prx) A. K. (prx)


Lesenswert?

W.S. schrieb:
> Das heißt, du kannst die aktuelle Uhrzeit in deinen Record schreiben.

Eine echte Uhrzeit ist dafür nicht nötig. Eine einfache Zählvariable 
reicht.

Beitrag #7049149 wurde vom Autor gelöscht.
von W.S. (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Eine echte Uhrzeit ist dafür nicht nötig.

Bei einer wenigstens so einigermaßen passabel gemachten Systemuhr hat es 
die ohnehin, egal ob hier grad mal unbedingt nötig oder nicht.

Wenn ich mich recht erinnere, dann hatte ich hier schon mal meine 
Systemuhr und Event-System gepostet. So etwas trägt kaum auf und man hat 
damit Events und delayed Events. Das reicht für alle Zwecke, bei denen 
man mit Zeiten von so etwa 1 ms und mehr arbeiten muß.

Recht oft würde eine Zeitauflösung von 10 ms auch ausreichen.

W.S.

von Wolfgang (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Eine echte Uhrzeit ist dafür nicht nötig.

Eine echte Uhrzeit mit SZ/WZ-Umstellung und Schaltsekunden ist dafür 
sogar ausgesprochen ungeeignet.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.