Hallo zusammen!
Ich bin auf der Suche nach einer eleganten Lösung um Befehle und Parameter über den UART zu empfangen. Ich möchte das Problem möglichst effizient lösen, d.h. unnötigen Code und Rechenzeit vermeiden. Auch soll es möglichst fehlersicher sein, d.h. ich will einerseits nichts verpassen, was ankommt, und andererseits nicht im Programm hängen bleiben, wenn plötzlich die Kommunikation abbricht.
Ich habe mich zum UART weitgehend eingelesen und schon einiges ausprobiert und sehe grundsätzliche mehrere Wege, wie ich das angehen könnte. Irgendwo ist aber immer ein Haken.
Ich denke, ich bin nicht der einzige, der ein solches Problem zu lösen hat, daher wollte ich hier mal nach Ansätzen und Erfahrungen fragen, bevor ich mir weiter den Kopf darüber zerbreche.
Zum Hintergrund: Es geht um einen Controller für eine Haussteuerung. Die Main Loop prüft bisher den Status von Eingängen an einem Schieberegister sowie einige Timer-gekoppelte Variablen zur zeitlichen Steuerung. Wenn etwas passiert (Schalter betätigt, Timer abgelaufen) dauert ein Durchlauf wenige Millisekunden.
Nun soll die Möglichkeit für Befehle von einer Zentrale ergänzt werden. Für ein bisschen Lesbarkeit stelle ich mir am Anfang einen "sprechenden Befehl" Befehl vor wie z.B. "rly" für das Ansteuern eines Relais oder "isw" für einen Stromstoßschalter (impulse switch). Auf den Befehl folgt eine Zahl, welche den Index des Relais etc. angibt, dann der Status, der gesetzt werden soll, sowie ein Parameter für zeitabhängiges Wiederausschalten. Befehle könnten also z.B. so aussehen:
- "rly 5 1 3600" (Relais Nr. 5 einschalten und nach 3600 Sekunden wieder ausschalten)
- "isw 2 1 0" (Stromstoßschalter Nr. 2 einschalten, nicht automatisch wieder ausschalten)
Am einfachsten scheint mir gepufferter Eingang mit Bytematch Interrupt. Der Befehl wird samt Parametern als Text gesendet. Befehl und Parameter sind mit " " oder TAB getrennt, eine Nachricht wird z.B. mit CR abgeschlossen. In der Interrupt Routine wird die Nachricht aus dem Puffer in eine Variable übertragen, welche dann in der Main Loop weiterverarbeitet wird, d.h. an den Trennzeichen zerlegt wird und die Parameter werden mittels Val() von Text in Zahl gewandelt.
Vorteile:
+ gepufferter Eingang
+ geschlossene Verarbeitung einer vollständigen Nachricht
Nachteile:
- erhöhter Datentransfer für die Parameter als Text statt als Byte oder Word
- erhöhte Rechnezeit und Programmgröße durch Umwandlung String -> Byte / Word
Etwas mehr Charme hätte die Verwendung von Inputbin um die Variablen für die Parameter direkt zu füllen. Aber das bekomme ich nicht wirklich hin. Mit Bytematch wird nicht zu funktionieren, da das Bytematch Zeichen nicht den Weg in den Puffer findet. Selbst wenn sehe ich hierbei das Problem, dass das Steuerzeichen nicht von einem Wert für einen Parameter unterschieden werden kann. Ich hätte also Schwierigkeiten z.B. die Zahl 13 als Zahl und nicht als CR zu übertragen.
Ich müsste dann den Serialin nur Puffern ohne den Bytematch Interrupt zu verwenden. In der Main Loop müsste ich dann immer schauen, ob etwas angekommen ist, und ggf. weiter verarbeiten. Hier habe ich aber die Schwierigkeit, dass ischarwaiting() nicht anzeigt, ob etwas da ist, oder nicht. Das geht anscheinend nur, wenn der Serialin nicht gepuffert ist. Da Inkey und Inputbin etc. eine Null liefern, wenn nichts da ist, kann ich das nicht von einer "echten" Null unterscheiden.
Inputbin würde auch das Programm anhalten, wenn es (noch) nichts zu lesen gibt. Wenn die Kommunikation an ungünstiger Stelle abbricht, würde das Programm hängen bleiben. $Timeout könnte hier helfen, aber ich vermute, dass inputbin im Fall eines Timeouts eine Null zurück gibt, welche ich dann auch nicht von einer echten Null unterscheiden kann.
Den UART ungepuffert zu nutzen damit ich ischarwaiting verwenden kann, scheint mir bei der Durchlaufzeit der Main Loop im Ereignisfall zu riskant, da ich bei hohen Baudraten Zeichen verpassen werde.
Was ich auch durchdenke und ausprobiere, irgendwas ist immer
Aber vielleicht hat hier jemand schon etwas ähnliches gemacht und hat eine gute Anregung für mich. Vielleicht habe ich ja auch irgendwas falsch verstanden oder beim Ausprobieren falsch gemacht und obige Überlegungen stimmen so einfach nicht
Ich würde mich freuen, wenn jemand helfen kann
Für eure Unterstützung vielen Dank im Voraus
Viele Grüße,
Michael
Ich bin auf der Suche nach einer eleganten Lösung um Befehle und Parameter über den UART zu empfangen. Ich möchte das Problem möglichst effizient lösen, d.h. unnötigen Code und Rechenzeit vermeiden. Auch soll es möglichst fehlersicher sein, d.h. ich will einerseits nichts verpassen, was ankommt, und andererseits nicht im Programm hängen bleiben, wenn plötzlich die Kommunikation abbricht.
Ich habe mich zum UART weitgehend eingelesen und schon einiges ausprobiert und sehe grundsätzliche mehrere Wege, wie ich das angehen könnte. Irgendwo ist aber immer ein Haken.
Ich denke, ich bin nicht der einzige, der ein solches Problem zu lösen hat, daher wollte ich hier mal nach Ansätzen und Erfahrungen fragen, bevor ich mir weiter den Kopf darüber zerbreche.
Zum Hintergrund: Es geht um einen Controller für eine Haussteuerung. Die Main Loop prüft bisher den Status von Eingängen an einem Schieberegister sowie einige Timer-gekoppelte Variablen zur zeitlichen Steuerung. Wenn etwas passiert (Schalter betätigt, Timer abgelaufen) dauert ein Durchlauf wenige Millisekunden.
Nun soll die Möglichkeit für Befehle von einer Zentrale ergänzt werden. Für ein bisschen Lesbarkeit stelle ich mir am Anfang einen "sprechenden Befehl" Befehl vor wie z.B. "rly" für das Ansteuern eines Relais oder "isw" für einen Stromstoßschalter (impulse switch). Auf den Befehl folgt eine Zahl, welche den Index des Relais etc. angibt, dann der Status, der gesetzt werden soll, sowie ein Parameter für zeitabhängiges Wiederausschalten. Befehle könnten also z.B. so aussehen:
- "rly 5 1 3600" (Relais Nr. 5 einschalten und nach 3600 Sekunden wieder ausschalten)
- "isw 2 1 0" (Stromstoßschalter Nr. 2 einschalten, nicht automatisch wieder ausschalten)
Am einfachsten scheint mir gepufferter Eingang mit Bytematch Interrupt. Der Befehl wird samt Parametern als Text gesendet. Befehl und Parameter sind mit " " oder TAB getrennt, eine Nachricht wird z.B. mit CR abgeschlossen. In der Interrupt Routine wird die Nachricht aus dem Puffer in eine Variable übertragen, welche dann in der Main Loop weiterverarbeitet wird, d.h. an den Trennzeichen zerlegt wird und die Parameter werden mittels Val() von Text in Zahl gewandelt.
Vorteile:
+ gepufferter Eingang
+ geschlossene Verarbeitung einer vollständigen Nachricht
Nachteile:
- erhöhter Datentransfer für die Parameter als Text statt als Byte oder Word
- erhöhte Rechnezeit und Programmgröße durch Umwandlung String -> Byte / Word
Etwas mehr Charme hätte die Verwendung von Inputbin um die Variablen für die Parameter direkt zu füllen. Aber das bekomme ich nicht wirklich hin. Mit Bytematch wird nicht zu funktionieren, da das Bytematch Zeichen nicht den Weg in den Puffer findet. Selbst wenn sehe ich hierbei das Problem, dass das Steuerzeichen nicht von einem Wert für einen Parameter unterschieden werden kann. Ich hätte also Schwierigkeiten z.B. die Zahl 13 als Zahl und nicht als CR zu übertragen.
Ich müsste dann den Serialin nur Puffern ohne den Bytematch Interrupt zu verwenden. In der Main Loop müsste ich dann immer schauen, ob etwas angekommen ist, und ggf. weiter verarbeiten. Hier habe ich aber die Schwierigkeit, dass ischarwaiting() nicht anzeigt, ob etwas da ist, oder nicht. Das geht anscheinend nur, wenn der Serialin nicht gepuffert ist. Da Inkey und Inputbin etc. eine Null liefern, wenn nichts da ist, kann ich das nicht von einer "echten" Null unterscheiden.
Inputbin würde auch das Programm anhalten, wenn es (noch) nichts zu lesen gibt. Wenn die Kommunikation an ungünstiger Stelle abbricht, würde das Programm hängen bleiben. $Timeout könnte hier helfen, aber ich vermute, dass inputbin im Fall eines Timeouts eine Null zurück gibt, welche ich dann auch nicht von einer echten Null unterscheiden kann.
Den UART ungepuffert zu nutzen damit ich ischarwaiting verwenden kann, scheint mir bei der Durchlaufzeit der Main Loop im Ereignisfall zu riskant, da ich bei hohen Baudraten Zeichen verpassen werde.
Was ich auch durchdenke und ausprobiere, irgendwas ist immer



Für eure Unterstützung vielen Dank im Voraus

Viele Grüße,
Michael