Frage zur Timerprogrammierung und Überlauf

Gast #3798213
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
Gast #3798238
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.
(Firma: Vescomp) #3798454
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...
Gast #3798931
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
Gast #3798948
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
#3798955
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.
#3798959
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?
#3798967
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
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren