Meine Problematik: Ich habe einen Satz UART Routinen (ARM M0) implementiert, die an sich schon mal bestens funktionieren. Nur für einen Fall fällt mir kein sauberer Lösungsansatz ein. Mein uC erwartet Strings, die ein definiertes String-Ende Kennzeichen haben (In meinem Fall FF FF FF). Prinzipiell gehe ich so vor: Pseudocode ISR_RX: RX-Byte -> FIFO Setzte RX-Flag In Main() if (RX-Flag) getStr() getStr(): Lese FIFO in ReceivedString[] bis FIFO leer oder String-Ende if (String-Ende) Setzt getString-Flag Das geht alles super. Nun will ich einen Timeout für den kompletten String implementieren. Es könnte ja sein, dass die Verbindung abbricht, bevor das String-Ende Kennzeichen empfangen wurde, der String also nicht komplett ist. Der Teilstring steht nun in ReceivedString[] und falls irgendwann ein neuer String empfangen wird, steht der davor. Ich will nun eine Möglichkeit haben festzustellen, dass zwischen 2 empfangenen Zeichen eine Zeit > timeout aufgetreten ist, und die älteren für ungültig erklärt werden. Bisher ist mir nur eingefallen, einen Timestamp beim Empfang zu generieren und mitzuführen. Allerdings müßte der ja dann auch im FIFO mitgeführt werden? Gibt es da bessere Ansätze? Reiner
Reiner W. schrieb: > Gibt es da bessere Ansätze? Einen Timer starten. Der wird mit dem Empfang des Stringendes gestoppt, sonst läuft er weiter und bei einem gewünschten Wert ruft er eine Routine auf, die den Timeout meldet, wohin auch immer, oder es wird ein Flag gesetzt. Man kann den Timer bei jedem empfangenen Zeichen auf Null setzen, dann wird der Timeout nur durch eine lange Sendepause ausgelöst. Oder man startet den Timer mit dem ersten empfangenen Zeichen, dann gibt es einen Timeout wenn die maximale Zeit für einen Record verstrichen ist. Oder man startet mit dem Start der Empfangsroutine, dann gibt es einen Timeout nach der maximalen Antwortszeit (das ist nicht das gleiche). Es gibt also viele Möglichkeiten. Georg
Und ganz wichtig, wenn der Timeout aufgetreten ist löscht man den FIFO. Ich gehe in dem Fall einfach mal davon aus das der vorhergehende String verarbeitet wurde bis der nächste kommt. Wenn nicht dann bleibt nur den FIFO von hinten zu löschen bis zur Stringendemarkierung des vorherigen. Sascha
Georg schrieb: > > Einen Timer starten. Der wird mit dem Empfang des Stringendes gestoppt, > Ja, das hab ich auch ünerlegt. Der Timer wird in der ISR gestartet. Die String-Ende Erkennung mach ich allerdings nicht in der ISR. Die Zeit zwischen tatsächlichem String-Ende und dessen Erkennung ist also davon abhängig, was der uC sonst noch so zu tun hat. Wenn timeout aber entsprechend dimensioniert ist, sollte man evtl. mit diesem Fehler leben können. Reiner
Das Ende eines Strings per timeout ? Sowas Bescheuertes. Eine Meldung muss natuerlich immer die eigene Laenge enthalten, dann kann man zaehlen. Das Problem des Timeouts ist die nicht-Vorhersagbarkeit des PC UARTS. Der PC kann irgend eine Blockgroesse aus Mal Senden, sich dann irgendwelche Zeit lassen, und dann den Rest nachschieben. Womit irgendwelche Zeit in die mehrere 100ms gehen kann. Immer die maximale Zeit als Timeout vorzugeben ist extrem ineffizient. Aendere das Protokoll sodass du zehlen kannst.
Sascha W. schrieb: > Und ganz wichtig, wenn der Timeout aufgetreten ist löscht man den > FIFO. Ja, der ist doch dann schon leer? Ich überführe ja den Fifo Inhalt mit getStr() in ReceivedString[], auch wenn der nicht komplett ist. Ich müsste also den dann löschen. Ich dachte jetzt an sowas: UART-RX -> Start Timeout-Timer (setze Timer auf 0) Timer-Ablauf -> lösche ReceivedString[] (Fifo sollte eigentlich leer sein) Führt aber dazu, dass der Timer generell in Sendepausen ausgelöst wird (nicht nur im Fehlerfall).
Joggel schrieb: > Das Ende eines Strings per timeout ? Sowas Bescheuertes. Eine > Meldung > muss natuerlich immer die eigene Laenge enthalten, dann kann man > zaehlen. > ja, ich geb das mal an die NEXTION Leute weiter, dass die ihr Protokoll bitte ändern sollen,-)
Joggel schrieb: > > Das Problem des Timeouts ist die nicht-Vorhersagbarkeit des PC UARTS. > Der PC kann irgend eine Blockgroesse aus Mal Senden, sich dann > irgendwelche Zeit lassen, und dann den Rest nachschieben. Womit > irgendwelche Zeit in die mehrere 100ms gehen kann. Das ist genau der Grund, warum ich mich damit schwer tue. Aber was solls. Die eigene Länge zählen, oder was auch immer, löst ja nicht das Problem, dass der uC irgendwann entscheiden muss, ob er noch länger auf ausstehende Daten warten soll. Und im Übrigen ging es nicht darum, dem Timeout als Stringende zu verwenden. Reiner
Da das Hauptprogramm den Stringanfang womöglich schon aus der FIFO geholt hat, muß im Fehlerfall auch das Hauptprogramm den String ungültig machen, denn der Interrupt kommt ja nicht mehr an die Daten. Das einfachste wäre es wohl, bei Timerablauf eine spezielle Kennung in die FIFO zu schreiben, damit das Hauptprogramm weiß, daß der String unvollständig ist. Alternativ könnte man auch die Zeitüberwachung dem Hauptprogramm überlassen. Zeitstempel merken, wenn etwas empfangen wurde, und gelegentlich nachsehen, ob der Zeitstempel schon zu alt und damit der bisher empfangene String ungültig ist. Man braucht hier ja keinen Präzisionstimer. Je nach Anwendung kann man den Timeout ja auch recht großzügig definieren, so daß der PC damit kein Problem bekommt, sofern er nicht sowieso überlastet ist.
Nosnibor schrieb: > Da das Hauptprogramm den Stringanfang womöglich schon aus der FIFO > geholt hat, muß im Fehlerfall auch das Hauptprogramm den String ungültig > machen, denn der Interrupt kommt ja nicht mehr an die Daten. In der Tat. Habts jetzt so gelöst: Pseudocode ISR_RX: RX-Byte -> FIFO Setzte RX-Flag Start/Reset uartCmdCompleteTimer //der TimeOut Timer In Main() if (RX-Flag) getStr() if (uartCmdCompleteTimer vorhanden und abgelaufen) clearStr() getStr(): Lese FIFO in ReceivedString[] bis FIFO leer oder String-Ende if (String-Ende) Setzt getString-Flag release uartCmdCompleteTimer //<- das sollte ich evtl. atomic machen clearStr(): setzte Pointer des letzten gelesenen Zeichen in ReceivedString[] auf 0 Das läuft soweit gut. Zumindest hab ich mal die Verbindung abgebrochen. Nicht komplett empfangene Strings werden sicher gelöscht. Den Fifo muss ich nicht löschen, da da getStr() ja den fifo immer komplett oder bis zum Endkennzeichen löscht. Muss noch mal auf evtl. Seiteneffekte testen, dann sollte das so gehen. Den Release des Timers in getStr() hab ich drin, damit in main() das clearStr() nur aufgerufen wird, falls überhaupt was empfangen wurde. Ist zwar nicht unbedingt nötig, muss ja aber nicht sein. Muss mal sehen, ob ich den release evtl. atomic machen muss, da ja just in dem Moment wieder ein RX-IR kommen könnte. Ich danke Euch für die hilfreichen Tipps! Reiner
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.