Forum: Mikrocontroller und Digitale Elektronik UART receive timeout?


von Fabian K. (fabian_k)


Lesenswert?

Hallo,

mein Programm (läuft auf einem Atmega8) empfängt alle 5ms neue 
Steuerdaten über UART. Der UART-Empfang ist interrupt-gesteuert. 
Außerdem werden alle Timer für die weiteren Funktionen benötigt.

Ich würde nun gerne einen Fehlermechanismus einbauen:
Wenn der AVR z.B. 10ms keine Daten per UART empfängt, soll eine 
Fehlerroutine aufgerufen werden.

Leider werden alle Timer gebraucht, somit fällt die Lösung, nach jedem 
erfolgreichem Empfang einen Timer zu starten, schonmal weg.

Hat jemand eine Idee, wie ich das sonst realisieren könnte?

Danke im voraus
Fabian

von spess53 (Gast)


Lesenswert?

Hi

>Leider werden alle Timer gebraucht, somit fällt die Lösung, nach jedem
>erfolgreichem Empfang einen Timer zu starten, schonmal weg.

Ein Timer kann durchaus mehrere Funktionen erfüllen. Erzähle mal, was du 
mit den vorhandenen Timern machst.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Fabian K. schrieb:

> Leider werden alle Timer gebraucht,

Und?
Es ist nicht verboten, einen Timer für mehr als 1 Sache zu benutzen.

> somit fällt die Lösung,
> nach jedem erfolgreichem Empfang einen Timer zu starten, schonmal
> weg.

Du musst ihn ja nicht dezidiert starten.
Lass ihn doch laufen. Hauptsache der Timer benachrichtigt regelmässig. 
Ob das Timeout jetzt genau 5ms beträgt, oder sich im Bereich 5 bis 10ms 
bewegt, ist doch in den meisten Fällen wurscht.

Timer lässt man sowieso nach Möglichkeit durchlaufen und stellt sie sich 
so ein, dass man eine der Applikation angemessene Basiszeit hat. Hast du 
einen Timer, der zb alle 1ms einen Overflow erreicht, dann gibst du dir 
in die Overflow ISR rein

volatile uint8_t uartTimeout;

ISR( .... )
{
  if( uartTimeout > 0 )
    uartTimeout--;

  ...
}

mit jedem Zeichen, welches über die UART reinkommt, setzt du uartTimeout 
auf zb 7. 'Erwischt' du die Variable ja dabei, mal 0 zu werden, dann 
hattest du einen Timeout.

Ist dein Timer auf eine andere Geschwindigkeit eingestellt (aber kleiner 
als 5ms von Overflow zu Overflow), dann hast du halt andere Zahlen, aber 
das Prinzip ist nach wie vor das gleiche.

Ob derselbe Timer dann auch noch eine PWM erzeugt, oder in der ISR die 
Tasten entprellt werden, oder ob er dafür zuständig ist eine LED blinken 
zu lassen ... lass ihn doch das tun. Für dich ist nur wichtig, dass die 
ISR regelmässig alle x Zeiteinheiten aufgerufen wird. Und vielfache von 
x kann man ja leicht mit einer Variablen abzählen.

von Reinhard Kern (Gast)


Lesenswert?

Hallo,

zur Ergänzung: nimm einen Timer an mit einer Ablaufzeit von 1 ms, sowas 
in der Art braucht man fast in jedem Controllersystem. Dann zählst du in 
der Timer-Routine eine Variable jede ms hoch, ein UART-Empfang setzt 
diese Variable auf 0 zurück. Die Timerroutine stösst dann eine 
Fehlerbehandlung an, wenn der Wert grösser wird als 5.

Gruss Reinhard

von Flääsch Gordon (Gast)


Lesenswert?

Nee sowas stoesst man im main() an. Die interrupt routine generiert nur 
eine Boolean.

von Fabian K. (fabian_k)


Lesenswert?

Danke für die schnelle Antwort.
Ich werde also einfach in die ISR von einem der Timer eine (globale) 
Variable inkrementieren und beim Erreichen eines bestimmten Wertes 
(abhängig von der Timerzeit) die Fehlerroutine aufrufen.

So einfach, eigentlich hätt ich selbst draufkommen müssen, den Timer 
mehrfach zu nutzen (:

Danke nochmal
Fabian

von Bronco (Gast)


Lesenswert?

Fabian K. schrieb:
> Ich werde also einfach in die ISR von einem der Timer eine (globale)
> Variable inkrementieren und beim Erreichen eines bestimmten Wertes
> (abhängig von der Timerzeit) die Fehlerroutine aufrufen.

Dann denke an volatile und atomare Zugriffe ;)

von Reinhard Kern (Gast)


Lesenswert?

Flääsch Gordon schrieb:
> Nee sowas stoesst man im main() an. Die interrupt routine generiert nur
> eine Boolean.

So war das ja auch gemeint - für einen Anfänger aber vielleicht 
missverständlich ausgedrückt.

Wobei es nicht unmöglich ist, von der ISR in ein Unterprogramm 
zurückzukehren und erst von dort an den Ausgangspunkt, aber das gehört 
in die Schublade übelste Trickserei.

Übrigens braucht man nicht einmal eine Boolean - man kann einfach in 
main die Variable abfragen und eine Fehlerbehandlung einleiten, wenn der 
Schwellwert überschritten ist.

Was das atomare angeht: kritisch ist nur der Fall, dass während des 
Inkrementierens ein UART-Interrupt die Variable auf 0 setzt.

Gruss Reinhard

von Sascha W. (sascha-w)


Lesenswert?

Reinhard Kern schrieb:
> Was das atomare angeht: kritisch ist nur der Fall, dass während des
> Inkrementierens ein UART-Interrupt die Variable auf 0 setzt.
wenn er das inc/dec in der Timer-ISR macht, und das laden in der 
UART-ISR dann hat er kein Problem, da ja immer nur eine ISR läuft.

Sascha

von Reinhard Kern (Gast)


Lesenswert?

Sascha Weber schrieb:
> da ja immer nur eine ISR läuft.

Da kannst du im speziellen Fall recht haben, die Prioritätssteuerung des 
AVR kenne ich nicht, aber allgemeingültig ist die Aussage nicht. Und 
selbst bei einer "flachen" Prioritätsstruktur kann man das in der 
Abteilung schweinische Tricks umgehen und auch während der Timer-ISR 
einen UART-IRQ zulassen. Bei höheren Baudraten ist es sogar dringend zu 
empfehlen, den UART mit hoher Priorität zu bedienen.

In jedem Fall sollte ein atomares Increment zum Befehlssatz oder zum 
Handwerkszeug des Programierers gehören, notfalls in der Form

Disable Interrupt
Increment Variable
Enable Interrupt

Gruss Reinhard

von Thomas E. (thomase)


Lesenswert?

Reinhard Kern schrieb:
> Da kannst du im speziellen Fall recht haben, die Prioritätssteuerung des
> AVR kenne ich nicht, aber allgemeingültig ist die Aussage nicht.
Beim AVR, und um den geht es schliesslich, ist das kein Problem. Wer 
irgendwelche Hackermethoden bemüht, ist dann allerdings selber schuld, 
wenn es schiefgeht.
Und das:

Reinhard Kern schrieb:
> Disable Interrupt
> Increment Variable
> Enable Interrupt

geht gar nicht. Jedenfalls nicht in einer ISR. Das ist die totale 
Verschlimmbesserung.

mfg.

von Weingut P. (weinbauer)


Lesenswert?

Also beim AVR kenn ich das so, dass, während der Ausführung der ISR 
keine anderen ISR angesprungen werden, es sei denn in der ISR steht ein 
SEI ...

Wenn dann nach Abarbeitung der ISR mehrere andere Interrupts anstehen, 
dann gehts der Tabelle nach.

Das mit dem SEI in der ISR hat mich aber mal 3 Nächte Fehlersuche 
gekostet, das ist mir nur einmal passiert ... die ISR so kurz wie 
möglich halten hat sich bei mir besser bewährt.

von Reinhard Kern (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> geht gar nicht. Jedenfalls nicht in einer ISR. Das ist die totale
> Verschlimmbesserung.

Das ist viel zu sehr verallgemeinert. Im Original IBM BIOS ist der erste 
Befehl einer Interrupt Routine STI (Interrupts wieder ein) und das ist 
auch das empfohlene Verfahren für ISRs. Es ist also keineswegs 
unmöglich, es übersteigt nur deine Kenntnisse. Keineswegs alle 
Prozessoren sind so primitiv, dass es keine Interupts während einer 
Interruptbearbeitung gibt, das ginge auch garnicht, in einem komplexen 
System gibt es mehrere bis viele Prioritäten und ein IRQ höherer 
Priorität kann sowieso eine ISR niederer Priorität unterbrechen (nicht 
zu verwechseln mit der Priorität innerhalb einer solchen 
Prioritätsklasse, das ist wieder eine andere Sache).

Wenn du nicht glaubst dass sowas funktioniert schalte einfach deinen PC 
ein.

Gruss Reinhard

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.