Forum: Mikrocontroller und Digitale Elektronik Mikrocontroller Software - Hilfestellung für Timeout Implementierung


von Leonhard (Gast)


Lesenswert?

Hallo, ich auf meiner Applikation für einen 16 Bit Mikrocontroller einen 
Timeout realisieren bzw. implementieren und verwenden.

Ich habe die Möglichkeit einen Timer zu starten und zu stoppen.
An mehreren Codestellen möchte ich nun bei einem Fehlerfall bzw. nicht 
Ausführung von bestimmen Codestellen, dass der Timeout zuschlägt. Wie 
realisiert man prinzipiell so eine Timeout Funktionalität mit einem 
Timer ?

Vielen Dank im Voraus!

von Karl H. (kbuchegg)


Lesenswert?

> nicht Ausführung von bestimmen Codestellen, dass der Timeout zuschlägt.

Was soll 'zuschlagen' konkret heißen? Wie sehen diese 'bestimmte 
Codestellen' aus?


> Wie realisiert man prinzipiell so eine Timeout Funktionalität
> mit einem Timer ?

zb so, dass der Timer bei bestimmten Zählerständen oder Zählereignissen 
einen Interrupt auslöst. In der zugehörigen ISR kann man dann zb einen 
Zähler runterzählen solange der ungleich 0 ist.

An der Aufrufstellt setzt man den Zähler auf einen Wert ungleich 0 und 
flechtet eine regelmässige Abfrage auf diesen Zähler in den Code, zb in 
Schleifen ein

volatile uint8_t TimoutCounter;

ISR( .... )
{
  if( TimeoutCounter > 0 )
    TimeoutCounter--;
}

....

int main()
{
  ....

  TimeoutCounter = 5;   // maximal 5 Timer ISR AUfrufe
  Starte Timer;

  while( Ereignis nicht eingetroffen && TimeoutCounter != 0 )
  {
    mach was
    warte
  }
  Stoppe Timer;

  if( TimeoutCounter == 0 )
  {
    // zu spät. Das war ein Timeout
  }
  else {
    ....


Das ist jetzt nur eine Variante. Es gibt noch unzählige andere 
Möglichkeiten, je nachdem welche Möglichkeiten du für den Timer hast, 
wie schnell der zählt, wie sich das Verhältnis von Timergeschwindigkeit 
zu Zeitdauer für den Timeout verhält, etc.

von Ralf G. (ralg)


Lesenswert?

Na, den Timer einfach zählen lassen! Wenn alles sauber läuft, an den 
entsprechenden Stellen immer wieder auf '0' setzen. Am 
Hauptschleifenende prüfen, ob der kritische Wert überschritten wurde und 
das Programm reagieren lassen.

von Leonhard (Gast)


Lesenswert?

Danke für eure Vorschläge.

Ich möchte allerdings einen Timeout in einem von mir geschriebenen 
Klasse einsetzen. In der Main While Schleife will ich nicht auf einen 
Timeout warten oder sonst irgendwas. Dies sollte alles in der Klasse 
funktionieren.

von Karl H. (kbuchegg)


Lesenswert?

Leonhard schrieb:
> Danke für eure Vorschläge.
>
> Ich möchte allerdings einen Timeout in einem von mir geschriebenen
> Klasse einsetzen. In der Main While Schleife will ich nicht auf einen
> Timeout warten oder sonst irgendwas. Dies sollte alles in der Klasse
> funktionieren.

Dann wäre zb eine Möglichkeit, dass du eine Callbackfunktion beim Timer 
registrierst, die in der ISR aufgerufen wird, wenn die Zeit abgelaufen 
ist. Das kann unter Umständen aber etwas tricky werden.

Eine andere Möglichkeit wäre, wenn jede derartige Klasse der 
Hauptschleife eine Funktion zur Verfügung stellt, mit der Bitte, dass 
die von der Hauptschleife regelmässig aufgerufen werden soll, weil die 
Klasse dann ihre ausstehenden Timeouts durchcheckt.

Denk dir was aus. Sei kreativ. In der Programmierung gibt es selten 
DAS eine Patentrezept mit dem man alles erschlagen kann. Aber es gibt 
Grundideen, Grundgedanken, die man in etwas angewandelter Form auf 
Problemstellungen loslassen kann.
Solche Aufgabenstellungen schaffst du im realen Leben mit links, wenn du 
8 verschiedene Aufgaben bearbeiten sollst und nur eine einzige Uhr zur 
Zeitkontrolle zur Verfügung hast.

von Ralf G. (ralg)


Lesenswert?

Was ist denn ein Timeout? - Wenn man einem Programmteil eine bestimmte 
Zeit lässt, ein Ergebnis zu liefern. Wenn in dieser Zeit keine Reaktion 
erfolgt, dann will man was unternehmen. Wo das ist, spielt keine Rolle. 
Diese Funktionalität kann man genauso einer Klasse zuordnen:

- Timer starten
- kritische Funktion aufrufen

- Timer auf '0' gezählt -> Ereignis auslösen -> kritische Funktion 
abbrechen

Wie man das konkret implementieren kann, weißt nur du. Das kommt auf den 
Compiler an.

von Chris (Gast)


Lesenswert?

was ist denn die reaktion die du ausführen willst wenns mal länger 
dauert? ist es eine überwachung für den unwahrscheinlichen fall das es 
mal länger dauert, was aber eigentlich nicht passieren sollte. Oder ist 
das länger brauchen einer funktion, ein gewolltes ereigniss das du 
bewusst ausnutzen willst?
ungewollt: watchdog verwenden
gewollt: timer zurücksetzen/starten vor der funktion und interrupt 
enablen, danach wieder disablen
soll es ohne interrupt funktionieren, dann kann dir wohl nur jemand 
helfen der deinen code kennt

von Leonhard (Gast)


Lesenswert?

Ich habe das ganze mal so implementiert:
1
void OnTimeOut(void) // Zyklischer Timer, wird immer alle 10 ms ausgeführt
2
{
3
  if(FlagStartTimer == 1 && TimeOutCnt > 0)
4
    TimeOutCnt--;
5
6
  if(FlagStartTimer == 1 && TimeOutCnt == 0)
7
  {
8
    FlagStartTimer   = 0;
9
    
10
    StoppTimer();
11
  }
12
}

Timer starten:
1
FlagStartTimer = 1;
2
TimeOutCnt     = 50; // 10 ms * 50 = 500 ms

Timer stoppen:
1
FlagStartTimer = 0;

von Peter D. (peda)


Lesenswert?


von Leonhard (Gast)


Lesenswert?

Hallo Peter,

danke für den Link. Was hat dies mit meinem Problem zu tun ?

von Karl H. (kbuchegg)


Lesenswert?

Leonhard schrieb:
> Hallo Peter,
>
> danke für den Link. Was hat dies mit meinem Problem zu tun ?

Mit einem 'Multitask' System sind Timeouts relativ banal umzusetzen


  for( i = 0; i < 20 && !receivedCharacterFromUart(); i++ )
    task_sleep( 10 );

ist zb ein banaler Timeout in einem Thread der auf Zeichen von der UART 
wartet. Dadurch dass in der Schleife die Rechenzeit immer wieder an 
andere Tasks abgegeben wird, können die weiterlaufen und nach der 
angegebenen Zeit (+- ein paar Zeiteinheiten) kriegt der Task wieder die 
Kontrolle um nachzusehen, ob an der UART etwas eingetrudelt ist. Wenn 
ja, hört er auf zu schleifen. Und wenn die Zeit (definiert durch die 
Anzahl der Schleifenwiederholungen mit der Sleep-Zeit) abgelaufen ist, 
ebenso.

In einem Singletask System wäre das
  for( i = 0; i < 20 && !receivedCharacterFromUart(); i++ )
    _delay_ms( 10 );
tödlich, da _delay_ms nur Zeit verbrutzelt. Aber das tut ja task_sleep 
nicht. Es wird zwar auch Zeit abgewartet, aber andere Tasks kriegen die 
Gelegenheit selbst wieder Arbeit zu machen.

von Peter D. (peda)


Lesenswert?

Leonhard schrieb:
> danke für den Link. Was hat dies mit meinem Problem zu tun ?

Nun, Du stellst den Callback hinein, daß er nach dem Timeout zuschlägt.
Und bist Du vor dem Timeout fertig, nimmst Du den Callback wieder raus.


Peter

von Leonhard (Gast)


Lesenswert?

Folgende Angaben habe ich hier nicht erwähnt.

Ich verwende kein Betriebssystem und somit habe ich auch keine 
Multitasking Funktionalität.

Ich möchte in der neuen Klasse (objektorientierter Ansi C Code) eine 
Timeout-Funktionalität einbauen. Einen Timer kann ich aufsetzen und auch 
beenden. Ich hab noch Probleme, wie man geschickt dies Implementieren 
könnte.

von Ralf G. (ralg)


Lesenswert?

Leonhard schrieb:
> Ich verwende kein Betriebssystem und somit habe ich auch keine
> Multitasking Funktionalität.

Deswegen ja auch das 'Multitasking des kleinen Mannes' von Peter.

Leonhard schrieb:
> Ich möchte in der neuen Klasse (objektorientierter Ansi C Code) eine
> Timeout-Funktionalität einbauen. Einen Timer kann ich aufsetzen und auch
> beenden. Ich hab noch Probleme, wie man geschickt dies Implementieren
> könnte.

Das stand schon weiter oben.

Du solltest jetzt mal gezielt die ansprechen, die dein Compilersystem 
kennen!
Allgemein ist eigentlich alles gesagt.

von W.S. (Gast)


Lesenswert?

Leonhard schrieb:
> Ich möchte in der neuen Klasse (objektorientierter Ansi C Code) eine
> Timeout-Funktionalität einbauen.

Du soltest dir zu allererst einmal darüber klar werden, was du 
eigentlich willst. Wozu sollte ein "Timeout" dienen?

Ich nehme mal an, daß du schlichtweg prozedural, also blockierend deine 
Programme schreibst:
 while (Ereignis noch nicht eingetreten) tu_nix_ausser_trampeln;
 Behandle_Ereignis();

Und da du dich mit sowas an jeder Ecke selber blockierst, suchst du nach 
einer Möglichkeit, aus solchen Blockaden herauszukommen - ohne zu 
begreifen, daß dies ein hausgemachtes Problem ist, das man mit einer 
anderen Programmierweise überhaupt nicht hat.

Also: programmiere lieber ereignisorientiert:
 if (Ereignis eingetreten) Behandle_Ereignis();
 if (was_anderes_gewesen) Reagiere_auf_das_Andere()
 if (nochwas) Tu_Nochwas()
usw. immer im Kreise. Es ist schlichtweg die Ereignis-Loop.

Das ist zugleich die Lösung für dein "Timeout-Problem", das du mit einem 
simplen systemweiten Uhrcounter erledigen kannst:
 Starte_eine_Aktion();
 LetzterTermin = Uhrzeit + xxx Millisekunden;
 ...
 ...
 if (Ereignis eingetreten)
 { Behandle_Ereignis();
   LetzterTermin = ungültig;
 }
 ....
 if (LetzterTermin < Uhrzeit)
 { Cancele_die_Aktion()
   LetzterTermin = ungültig;
 }
 .. kümmere_dich_um_andere_Ereignisse()...

So etwa. Ich hoffe, du hast das gedankliche Prinzip herausgelesen.

W.S.

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.