Forum: Mikrocontroller und Digitale Elektronik Frage zur Timerprogrammierung und Überlauf


von Hannes (Gast)


Lesenswert?

Hallo,

ich habe in einem Projekt die folgende Timerprogrammierung gefunden:
1
if (MicroSecTimer() - ui32Time) > WERT_IN_US) 
2
{
3
 //Do Something
4
}
5
else
6
{
7
 //Do something else
8
}

Die variable "ui32Time" wird an einer Stelle mit "ui32Time = 
MicroSecTimer()" vorbelegt.

Bei einem Überlauf des Microsekunden Zählers wird doch für die Zeit 
WERT_IN_US die Bedingung false. Zugegeben dauert es bei 32 Bit über 70 
Minuten, aber wie programmiert man so ein Konstukt richtig. Ich habe es 
schon öfters gesehen. Es ist mir aber immer suspekt geblieben. 
Wenngleich es sehr elegant anmutet :-)

Hannes

von holger (Gast)


Lesenswert?

>Bei einem Überlauf des Microsekunden Zählers wird doch für die Zeit
>WERT_IN_US die Bedingung false.

Nein, wird es nicht. Dort wird mit einer Differenz gerechnet.
Die stimmt auch mit Überlauf noch. Man muss sich nur mal ein
Beispiel berechen wo der Überlauf auftritt. Dann sieht man
das das so geht.

von Karl H. (kbuchegg)


Lesenswert?

Eine weitere wesentliche Zutat duerfte darin bestehen, dass es sich wohl 
um unsigned Werte handelt.
Unsigned gerechnet ergibt 5 - 8 nun mal nicht minus 3. Bei unsigned 
existieren keine negativen Werte.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Hannes schrieb:
> Bei einem Überlauf des Microsekunden Zählers wird doch für die Zeit
> WERT_IN_US die Bedingung false. Zugegeben dauert es bei 32 Bit über 70
> Minuten, aber wie programmiert man so ein Konstukt richtig. Ich habe es

 Nein, aber bei zwei Überläufen schon ;-)
 Deswegen benutzt man auch sowas wie ui32LastTime und aktualisiert die
 ui32Time wenn die Bedingung erfüllt ist...

von holger (Gast)


Lesenswert?

> Nein, aber bei zwei Überläufen schon ;-)

Das ist natürlich richtig. Und "WERT_IN_US" darf auch nicht
grösser sein als ein uint32_t. Dann geht das auch in die Hose.

von Hannes (Gast)


Lesenswert?

hallo,

danke für Eure Antworten. Warum wird aber dann der else-Zweig nach jedem 
Timerüberlauf von TIMER_TIM->CNT immer wieder kurz angesprungen?
1
uint32_t EsvTimer = 0; // Global initialisiert
2
3
// Die Abfrage wird zyklisch aufgerufen.
4
if((TIMER_TIM->CNT - EsvTimer) > ((int)3e6)) // den (int) cast habe ich auch schon mal in uint32_t geändert, geht aber auch nicht.
5
 SET_LED_DEBUG;
6
else
7
 CLR_LED_DEBUG; // Bei jedem Timerüberlauf wird dies angesprungen


Hannes

von Peter D. (peda)


Lesenswert?

Hannes schrieb:
> Warum wird aber dann der else-Zweig nach jedem
> Timerüberlauf von TIMER_TIM->CNT immer wieder kurz angesprungen?

Wenn der Zählbereich 70min beträgt, kannst Du eben nur Zeitdifferenzen 
<70min damit timen.

Üblicher Weise nimmt man sowas ja nur für kurze Delays und nicht als 
Echtzeituhr.

von Hannes (Gast)


Lesenswert?

Hallo Peter,

das ist auch keine Echtzeituhr :-)

Ich möchte aber verhindern, das im Normalbetrieb dieFunktion alle 70 min 
für 3s ausgeführt wird. habe ich da so eine Chance oder muss ich die 
Timerroutine komplett ändern?

Hannes

von Karl H. (kbuchegg)


Lesenswert?

Hannes schrieb:

> if((TIMER_TIM->CNT - EsvTimer) > ((int)3e6)) // den (int) cast habe ich

Man sollte auch mal ein bischen nachdenken was man da tut. Auch über 
Datentypen und ihre damit verbundenen Wertebereiche.

3e6 ... ich hab nichts gegen wissenschaftliche Schreibweise. Aber wen 
man gedankenlos vorgeht, dann versteckt man hier etwas wichtiges. 3e6 
ist die 'wissenschaftliche Schreibweise' für 3 Millionen.

Wie gross ist noch mal der Wertebereich eines int?
Auf einem Arduino ist ein int 16 Bit gross. Der Zahlenbereich geht daher 
von -32768 bis +32767. Das möchte ich mal sehen, wie du 3 Millionen in 
einem 16 Bit int unterbringst, ohne dass dir irgendwas verloren geht.

Generell: Halte dich mit Casts etwas zurück. Casts sind Waffen! Manchmal 
sind sie die Lösung für ein Problem. Aber eine Inflation an Casts ist 
meistens ein Zeichen dafür, dass der Programmierer nicht wirklich weiß 
was er da tut und einfach mal eine Handvoll Casts auf das Problem 
loswirft, in der Hoffnunf das das das Problem schon irgendwie regeln 
wird.

von Karl H. (kbuchegg)


Lesenswert?

Hannes schrieb:

> Ich möchte aber verhindern, das im Normalbetrieb dieFunktion alle 70 min
> für 3s ausgeführt wird. habe ich da so eine Chance oder muss ich die
> Timerroutine komplett ändern?

Du brauchst überhaupt nichts tun (solange alle beteiligten Akteure 
unsigned sind).
Einfach die beiden Zeiten voneinander abziehen und nachsehen ob die 
Differenz größer als die vorgesehene Differenz ist. Den Rest regelt die 
Art und Weise, wie unsigned Rechnerei in C definiert ist.

(Ende - Anfang) ergibt IMMER die Anzahl der 'Ereignisse' dazwischen. 
Selbst wenn da ein Variablenüberlauf dazwischen liegt und solange es nur 
1 Überlauf ist und der Wertebereich grundsätzlich ausreicht um die 
Differenz darstellen zu können. Einfach mal selber binär mit 2 Zahlen 
auf dem Papier ausprobieren und selber rechnen?

von Peter D. (peda)


Lesenswert?

Hannes schrieb:
> Ich möchte aber verhindern, das im Normalbetrieb dieFunktion alle 70 min
> für 3s ausgeführt wird.

Ein Delay ruft man einfach nur solange auf, bis die Zeit rum ist, z.B.:
1
uint32_t delay = 0;
2
3
void start( uint32_t val )
4
{
5
  delay = val;
6
  EsvTimer = TIMER_TIM->CNT;
7
}
8
9
void wait( void )
10
{
11
  if( delay && ((TIMER_TIM->CNT - EsvTimer) > delay)){
12
      delay = 0;
13
      mache_was();
14
    }
15
  }
16
}

von Hannes (Gast)


Lesenswert?

Danke Peter :-)

Das mit dem verriegeln war der Trick!

Hannes

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.