UART Kommunikation

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • UART Kommunikation

      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 :S 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 a_14_3ef964b0

      Für eure Unterstützung vielen Dank im Voraus :thumbsup:

      Viele Grüße,
      Michael
    • Moin Michael,

      das Problem mit der Unterscheidung zwischen einem gesendeten Wert 13 und einem "CR" könntest Du lösen, indem Du Werte nicht als Bytes, sondern als Folge von ASCII-Zeichen überträgst. Der Wert 13 wäre dann eine 49 und eine 51, wohingegen eine empfangene 13 ist immer ein CR ist.
      Ich habe sowas mal gelöst, indem ich die einzelnen Parameter mit Semikolons getrennt habe (wie es z.B. jeder GPS-Empfänger macht). Dann ist es auch egal, wieviele Stellen ein Parameter hat.
      Konkret hatte ich ein Array von Strings definiert und vom Empfang eines UART-Bytes einen Interrupt auslösen lassen. In der ISR habe ich als erstes überprüfen lassen ob das empfangene Byte eine 13 war, dann wurde ein Fertig-Flag gesetzt. Als nächstes kam die Überprüfung ob es eine 59 war (Semikolon), in diesem Fall wurde der Index-Zähler des String-Arrays um eins inkrementiert. In allen anderen Fällen (Kein CR oder Semikolon) wurde der ASCII-Charakter des empfangenen Bytes einfach an den aktuellen String drangehängt.
      Dies hat die Hauptschleife nicht nennenswert beeinträchtigt, und wenn das "Fertig"-Flag gesetzt wurde, konnte die Hauptschleife die empfangenen Strings entsprechend weiterverwursten.
    • Das ist eher eine Frage der persöhlichen Vorliebe.
      ich bevorzuge den Klartext. Eine eigene Urxc-Routine kann die Daten sammeln und ein Flag setzen wenn eine Anforderung komplett ist.
      Die Word Umrechnung kann ca 3X schneller und Flash sparend sein wenn keine Long berechnet werden müssen. Dazu gibts die "mcsbyteint.lib"
      Noch schneller wäre eine Übertragung von Hex-Zahlen "rly 5 1 3600" -"rly 5 1 E10" oder "R5 1 E10"

      Binärübertragung sollte auch ein "fertig" Byte haben womit die Urxc_isr die Ankunft melden kann.
      Dann sollte vielleicht eine Checksumme mitgeliefert werden?
      Wie schlimm könnte etwas falsch verstandenes werden?
    • Daten zu übertragen kann sehr individuell gestaltet werden.
      Ich persönlich bevorzuge die Binäre Variante in Verbindung mit einem SerialIn-Buffer.
      Dabei verwende ich ein einfaches Protokoll mit Start-Byte, Stop-Byte, dazwischen je nach Anwendung ein Command-Byte und optional Daten.
      So ein Frame wird dann vom Empfänger mit ACK bzw. NACK bestätigt.
      Dafür sind bereits Bytes im Ascii-Code definiert, die man da verwenden kann.

      In deinem Fall könne das z.B. so von Statten gehen.
      Dieses Kommando "rly 5 1 3600" könne man so übertragen

      <STX><SET_RELAY><<RelayNr><Dauer><Checksum><EOT>

      STX ist das Startbyte und immer Fix, siehe ASCII-Tabelle
      SET_RELAY ist eine Constante, die eindeutig sein muss und als Commando dient. An diesem Kommando erkennt der Empfänger, wie lange das Frame ist. Es folgt also noch 1 Byt mit Relay-Nr und ein Word-Wert mit der Dauer, 1 Byte Checksumme und 1 Byte EOT (Stop-Byte).
      Relay-Nr gibt das Relay an, das geschaltet werden soll, 1 Byte, es ist quasi ein DatenByte
      Dauer gibt die Dauer an, wird als Word übertragen, 2 DatenByte
      Checksum kann ein Byte als Summe der Übertragenen Bytes sein.
      EOT bildet das Stop-Byte und ist ebenfalls immer fix, siehe ASCII-Tabelle

      Das Frame beinhaltet so 7 Byte.


      Mit dem SerialIn-Buffer kann man die Abfrage IsCharWaiting() verwenden und dann die Werte direkt in Variablen via InputBin einlesen.
      Der angegebene Variablen-Typ bestimmt, wieviel Bytes gelesen werden.

      Vorteil an der Methode:
      1. Weniger Datenbytes werden übertragen als bei ASCII-Text, dadurch ist die Übertragung auch schneller.
      2. Die Umwandlung von Strings in Variablen sowie das Split entfällt. Daten werden direkt in die Variablen gelesen (InputBin).
      3. Eine eigene UART-Routine muss man auch nicht programmieren und es gehen keine Bytes verloren.
      Der Sender muss natürlich das ACK abwarten, dann weiß er, dass die Daten beim Empfänger angekommen sind.
      Bei NACk wird nochmals gesendet.

      In dem Frame kann auch noch eine einfache Checksumme (Summe aller Bytes außer Stop-Byte und Checksumme) mitgesendet werden, dadurch erhöht sich die Datensicherheit bei der Übertragung. Man kann auch ein Wert mitsenden, der die Länge der Daten angibt. Vieles möglich!

      Empfangene Daten liegen so also erst mal im Serial-In-Buffer.
      Mit einer anderen Routine, die man einfach von der Hauptschleife aus regelmäßig aufruft, wird geprüft, ob ein Byte im Buffer liegt. Es kann übrigens auch über Systemvariablen geprüft werden, wieviel Bytes im Buffer liegen. Dann kann man schauen, welchen Wert das Command-Byte hat. Abhängig davon kann man verschieden weiter machen. Daten abfragen etc.
      Ich mache das gerne in Form einer Statemachine. So kann ich die Routine Byteweise den SerialIn lesen lassen. Sie entscheidet, wie die Daten gelesen werden.
      Sind die Daten komplett wird hier das Ack oder NACk geschickt und dem Hauptprogramm mitgeteilt, dass etwas auszuführen ist. Oder man macht das gleich in der Routine.

      Wenn das als Statemachine gemacht wird, werden andere Dinge im Controller nicht vernachlässigt. So wird also bei jedem Aufruf der Routine praktischerweise immer nur ein Byte aus dem SerialIn verarbeitet. Es geht nichts an Daten verloren und es wird auch nichts blockiert.

      Das mit dem Analog lesen haben die Vorredner ja schon gesagt. Ein Mux wirst du brauchen, den du auch ansteuern musst. Nur so kannst du die ganzen Analogen Messpunkte abdecken.
    • Michael W wrote:

      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.
      Ob du pufferst oder nicht macht hier keinen Unterschied, da der Compiler bei Buffered eine ISR hinzufügt, die die empfangenen Bytes in den Puffer ablegt. Das geht nicht in HW.
      Ich würde auch kein IsCharWaiting verwenden, wenn du längere Zeichenfolgen empfangen willst, weil dabei in der Regel die Abarbeitung unterbrochen wird, bis die komplette Folge übertragen ist.

      Ich verwende fast ausschließlich den URXC Interrupt für Zeichen zu empfangen, ohne Config Serialin oder IsCharWaiting oder so etwas. Im Interrupt kannst du dann entscheiden, ob du bei jedem empfangenen Zeichen schon auswertest, was reingekommen ist(so wie Einzeller das beschrieben hat) oder einfach nur in ein Array abspeicherst (das wäre wie Puffern). Das unterbricht dein Hauptprogramm nur kurz und du hast die volle Kontrolle was passiert. Ebenso kannst du direkt darauf reagieren, wenn kein Ende Zeichen nach einer gewissen Zeit kommt oder mehr Zeichen als erwartet übertragen werden. Natürlich ist das etwas mehr programmieraufwand.


      Einzeller wrote:

      das Problem mit der Unterscheidung zwischen einem gesendeten Wert 13 und einem "CR" könntest Du lösen, indem Du Werte nicht als Bytes, sondern als Folge von ASCII-Zeichen überträgst. Der Wert 13 wäre dann eine 49 und eine 51, wohingegen eine empfangene 13 ist immer ein CR ist.
      Ist das nicht genau das, was bei Print normalerweise passiert. Du überträgst halt einige Zeichen mehr und musst diese nachher wieder zu den richtigen Werten zusammensetzen.

      The post was edited 1 time, last by Franz ().

    • Hallo zusammen!

      Vielen Dank für eure schnellen Antworten und die hilfreichen Beiträge
      Ich habe unten meine Gedanken dazu zusammengefasst.
      Einen schönen Abend euch noch!

      Viele Grüße,
      Michael


      Einzeller schrieb:

      das Problem mit der Unterscheidung zwischen einem gesendeten Wert 13 und einem "CR" könntest Du lösen, indem Du Werte nicht als Bytes, sondern als Folge von ASCII-Zeichen überträgst.
      So war auch mein erster Gedanke, Zahlen auch einfach als Text senden und nach dem Empfang wieder in eine Zahl umwandeln. Ist einfach und wahrscheinlich auch pragmatisch, braucht aber z.B. für die Zahl 123 drei Bytes anstatt nur eines und dazu noch mehr Code und Rechenzeit für die Typumwandlung. Ich dachte, das geht vielleicht auch eleganter.


      Pluto25 schrieb:

      Das ist eher eine Frage der persöhlichen Vorliebe. ich bevorzuge den Klartext.
      Ich bevorzuge auch Klartext. Muss man nicht so viel kreuz und quer denken


      Pluto25 schrieb:

      Eine eigene Urxc-Routine kann die Daten sammeln und ein Flag setzen wenn eine Anforderung komplett ist.
      Da habe ich ein Stichwort zum Nachlesen, Urcx Bezüglich Uart Interrupt habe ich bisher nur über "config serialin = buffered, size = xxx, bytematch = 13" nachgedacht.
      Ist Urcx ein Interrupt, wenn ein Byte am UART empfangen wird? Ist das (zumindest prinzipiell) das gleiche wie ""config serialin = buffered" mit "bytematch = ALL"?


      Pluto25 schrieb:

      Die Word Umrechnung kann ca 3X schneller und Flash sparend sein wenn keine Long berechnet werden müssen. Dazu gibts die "mcsbyteint.lib"
      Das ist ein guter Hinweis. Momentan brauche ich nur Byte und Word, die Lib würde das effizienter machen.


      Pluto25 schrieb:

      Noch schneller wäre eine Übertragung von Hex-Zahlen "rly 5 1 3600" -"rly 5 1 E10" oder "R5 1 E10"
      Stimmt, das würde auch noch etwas sparen. Aber noch kann ich nicht fließend in Hex denken, das wäre dann nicht mehr richtig Klartext und ich müsste viel mehr nachdenken.


      Pluto25 schrieb:

      Binärübertragung sollte auch ein "fertig" Byte haben womit die Urxc_isr die Ankunft melden kann.
      Wie meinst du das Einfach eine Variable als Flag um im Hauptprogramm die Verarbeitung zu steuern? Die Flag für den Empfang eines einzelnen Bytes? Oder für den Abschluss eines Befehls?
      Vielleicht verstehe ich es, wenn ich mich zum Urxc schlau gemacht habe?


      Pluto25 schrieb:

      Dann sollte vielleicht eine Checksumme mitgeliefert werden?
      Ist einen Gedanken Wert, aber eher Bestandteil einer späteren Optimierung.


      Pluto25 schrieb:

      Wie schlimm könnte etwas falsch verstandenes werden?
      Die Welt wird nicht untergehen. Wenn kompletter Quatsch ankommt wird der Controller es nicht interpretieren können und sich beim Absender beschweren. Ansonsten hängt es davon ab, was falsch verstanden wird.
      Wird z.B. für den Parameter für das automatische Abschalten eine Null gelesen, weil wegen Verbindungsproblemen nichts mehr angekommen ist, würde das Gerät nicht ausgeschaltet werden. Schlimmstenfalls würde das Licht im Flur oder die Pumpe vom Gartenteich durchgehend laufen. Wird für den Index eines Relais eine 2 anstatt eine 3 verstanden, würde halt das falsche Gerät angehen. Einen "Index out of Range" könnte ich sicherheitshalber noch abfragen, das zuvor genannte wird eher schwierig, außer dann mit Checksum und Rückmeldung des empfangenen Befehls etc.

    • Mitch64 schrieb:

      Ich persönlich bevorzuge die Binäre Variante in Verbindung mit einem SerialIn-Buffer.

      Dabei verwende ich ein einfaches Protokoll mit Start-Byte, Stop-Byte, dazwischen je nach Anwendung ein Command-Byte und optional Daten.
      ...
      Den Ansatz mit Binären Daten und den Steuerzeichen hatte ich auch grob im Kopf. Vorteile wie du sagst liegen auf der Hand. Allerdings hat das nicht mehr so viel mit Klartext zu tun. Deswegen wollte ich wenigstens den eigentlichen Befehl lesbar halten. Text und Binärdaten zu mischen scheint aber nicht ganz so einfach zu sein.

      Ich hatte mich hieran schon mal grob versucht, aber bei der Umsetzung - Puffern, Abfragen ob was da ist, Auslesen mit Inputbin - hatte ich Probleme:


      Mitch64 schrieb:

      Mit dem SerialIn-Buffer kann man die Abfrage IsCharWaiting() verwenden und dann die Werte direkt in Variablen via InputBin einlesen.
      Das hatte bei mir nämlich nicht geklappt. Sobald ich "Config Serialin = buffered" drin hatte, hat IsCharWaiting() keine 1 mehr ausgegeben. Ich hatte mir das so erklärt, dass das empfangene Byte umgehend vom Eingangspuffer in den konfigurierten Puffer verlegt wird und deswegen im Eingangspuffer, welcher mit IsCharWaiting() abgefragt wird, nie etwas liegt. Aber dann scheint das Quatsch zu sein, und ich habe irgendwas anderes falsch gemacht. Werde damit nochmal etwas rumprobieren und mich dann ggf. mit einem konkreten Problem dazu nochmal melden.


      Mitch64 schrieb:

      In dem Frame kann auch noch eine einfache Checksumme (Summe aller Bytes außer Stop-Byte und Checksumme) mitgesendet werden, dadurch erhöht sich die Datensicherheit bei der Übertragung. Man kann auch ein Wert mitsenden, der die Länge der Daten angibt. Vieles möglich!
      Wenn die Grundlagen stimmen werde ich mich auch an solche Optimierungen wagen


      Mitch64 schrieb:

      Empfangene Daten liegen so also erst mal im Serial-In-Buffer.

      Mit einer anderen Routine, die man einfach von der Hauptschleife aus regelmäßig aufruft, wird geprüft, ob ein Byte im Buffer liegt. Es kann übrigens auch über Systemvariablen geprüft werden, wieviel Bytes im Buffer liegen. Dann kann man schauen, welchen Wert das Command-Byte hat. Abhängig davon kann man verschieden weiter machen. Daten abfragen etc.
      So dachte ich es mir auch, als Alternative zur Text Variante mit Bytematch Interrupt. Hing aber daran, dass bei gepuffertem Eingang (ohne Bytematch) IsCharWaiting() nicht funktioniert hatte (s.o.). Ggf. dann auf die Systemvariablen zugreifen. Aber wie schon gesagt, erstmal mit IsCharWaiting weiter ausprobieren.


      Mitch64 schrieb:

      Ich mache das gerne in Form einer Statemachine. So kann ich die Routine Byteweise den SerialIn lesen lassen. Sie entscheidet, wie die Daten gelesen werden.

      Sind die Daten komplett wird hier das Ack oder NACk geschickt und dem Hauptprogramm mitgeteilt, dass etwas auszuführen ist. Oder man macht das gleich in der Routine.
      Wenn das als Statemachine gemacht wird, werden andere Dinge im Controller nicht vernachlässigt. So wird also bei jedem Aufruf der Routine praktischerweise immer nur ein Byte aus dem SerialIn verarbeitet. Es geht nichts an Daten verloren und es wird auch nichts blockiert.
      Was ist eine Statemachine Noch was zum recherchieren


      Mitch64 schrieb:

      Das mit dem Analog lesen haben die Vorredner ja schon gesagt. Ein Mux wirst du brauchen, den du auch ansteuern musst. Nur so kannst du die ganzen Analogen Messpunkte abdecken.
      Meinst du mit Analog lesen die Übertragung in Textform? Was ist ein Mux? Und welche Anlogen Messpunkte?
    • Franz schrieb:
      Michael W schrieb:

      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.
      Ob du pufferst oder nicht macht hier keinen Unterschied, da der Compiler bei Buffered eine ISR hinzufügt, die die empfangenen Bytes in den Puffer ablegt. Das geht nicht in HW.
      Was meinst du mit "das geht nicht in HW"? HW = Hardware oder in diesem Kontext was anderes?
      Wie oben schon geschrieben hat es für IsCharWaiting in meinem Versuchsbeispiel einen Unterschied gemacht, ob der Uart Buffered war oder nicht. Was du schreibst untermauert eigentlich meine Vermutung: "...da der Compiler bei Buffered eine ISR hinzufügt, die die empfangenen Bytes in den Puffer ablegt". Also ist im Empfangspuffer nie was drin, weil die ISR das sofort leer räumt. Aber wie gesagt, werde das weiter testen.

      Franz schrieb:
      Ich würde auch kein IsCharWaiting verwenden, wenn du längere Zeichenfolgen empfangen willst, weil dabei in der Regel die Abarbeitung unterbrochen wird, bis die komplette Folge übertragen ist.
      Verwechselst du das gerade mit Waitkey??? IsCharWaiting prüft doch nur, ob was im Puffer liegt, und meldet - je nachdem - 0 oder 1 zurück. Danach geht es weiter im Text. Somit kann man mit IsCharWaiting erstmal prüfen, ob es überhaupt Sinn macht, etwas auszulesen. Oder nicht ?(


      Franz schrieb:

      Ich verwende fast ausschließlich den URXC Interrupt für Zeichen zu empfangen, ohne Config Serialin oder IsCharWaiting oder so etwas. Im Interrupt kannst du dann entscheiden, ob du bei jedem empfangenen Zeichen schon auswertest, was reingekommen ist(so wie Einzeller das beschrieben hat) oder einfach nur in ein Array abspeicherst (das wäre wie Puffern). Das unterbricht dein Hauptprogramm nur kurz und du hast die volle Kontrolle was passiert. Ebenso kannst du direkt darauf reagieren, wenn kein Ende Zeichen nach einer gewissen Zeit kommt oder mehr Zeichen als erwartet übertragen werden. Natürlich ist das etwas mehr programmieraufwand
      Wie schon zu Einzeller geschrieben, Urcx ist etwas, was ich nachschlagen muss.

      Franz schrieb:
      Einzeller schrieb:

      das Problem mit der Unterscheidung zwischen einem gesendeten Wert 13 und einem "CR" könntest Du lösen, indem Du Werte nicht als Bytes, sondern als Folge von ASCII-Zeichen überträgst. Der Wert 13 wäre dann eine 49 und eine 51, wohingegen eine empfangene 13 ist immer ein CR ist.
      Ist das nicht genau das, was bei Print normalerweise passiert. Du überträgst halt einige Zeichen mehr und musst diese nachher wieder zu den richtigen Werten zusammensetzen.
      Ja, so passiert es normal mit Print, glaube ich.
      Aber, wenn ich es richtig verstanden habe, ist es erstmal egal, ob ich nun Print, oder Printbin, oder Input, oder Inputbin etc. verwende. Momentan experimentiere ich eh nur über Konsole-Programme die nur Text schlucken. Trotzdem kann ich binäre Daten übertragen. Wenn ich z.B. die Zahl 48 übertragen will kann ich beim Sender (quasi mit Print) das Zeichen "0" senden und beim Empfänger mit Inputbin einlesen, in der zugehörigen Variable steht dann eine 48, der zugehörige ASCII Code. Natürlich gibt es im Detail Unterschiede, z.B. bei den Steuerzeichen CRLF die mit gesendet werden oder der Länge der Bytes die gelesen werden (Inputbin mit einer Word Variable liest direkt zwei Bytes).

      The post was edited 2 times, last by Michael W ().

    • Das Flag wäre eine Anweisung komplett Meldung.
      Hier wurde die Urxc verschiedendlich behandelt. Leider finde ich auf Anhieb nichts passendes.
      Es könnte etwa so aussehen

      Source Code

      1. $baud = 9600
      2. On Urxc Rx_da
      3. Enable Urxc
      4. Dim Rxbufer(16) as byte
      5. Dim Rxbyte as byte
      6. Dim Rxzaehler as byte
      7. Dim Rxneu as byte
      8. Enable Interrupts
      9. Do 'Mainloop
      10. if Rxneu = 1 then
      11. ...Auswertung
      12. Rxneu=0
      13. Rxzaehler=0
      14. end if
      15. ...
      16. Loop
      17. Rx_da:
      18. Rxbyte = UDR '*1
      19. If Rxbyte = 10 then '10 wegen CrLf
      20. Rxneu = 1
      21. else
      22. Rxbuffer(Rxzaehler) = Rxbyte
      23. If Rxzaehler < 16 then incr Rxzaehler '*2
      24. end if
      25. return
      26. '*1 Das Empfangsregister (UDR) zwischenspeichern
      27. '*2 Damit er nicht überläuft wenn Quatsch empfangen wird
      Display All
      Das Rxbyte ('*1) ist hier nicht nötig macht aber Sinn wenn die Isr noch weitere Aufgaben bekommt. z.B. selber auszuwerten. Oder die Baudrate so hoch ist das ein weiteres Byte angekommen ist bevor sie das erste verarbeitet hat. Der Avr würde es mit dem neuen Wert füllen sobalt es einmal gelesen wurde, heißt es würde sich mitten in der Isr ändern - chaos komplett.
    • Hallo Pluto25!

      Danke für den Code :thumbup:
      Habe ich glaube ich so weit verstanden.

      Die Fragen nach dem Urxc haben sich auch schon beantwortet.
      Hätte ich gestern besser mal zwei Minuten Google gefragt a_45_132ca9f5

      Ich werde die Tage mal versuchen etwas konkret umzusetzen.
      Einige neue Anregungen habe ich auf jeden Fall bekommen.
      Danke nochmal für eure Bemühungen!

      Viele Grüße,
      Michael
    • Michael W wrote:

      Verwechselst du das gerade mit Waitkey??? IsCharWaiting prüft doch nur, ob was im Puffer liegt, und meldet - je nachdem - 0 oder 1 zurück.
      Wenn du festgestellt hast, dass etwas vorhanden ist, liest du das ja normalerweise ein.
      Wenn du nur ein Byte einliest, geht das ohne Verzögerung, weil das Byte ja schon da ist.
      Liest du aber eine mehr-Byte Variable wie z.B. ein Word ein, sind de weiteren bytes noch nicht übertragen worden. Dann wartet die Einleseroutine. Und das kann bei einem 10 Zeichen String schon ziemlich lange dauern. Daher ist sowas mit Vorsicht zu geniessen, wenn man befürchtet, dass zeitkritische Bereiche nicht schnell genug dran kommen.
      Deswegen verwende ich fast nur direkt den URXC, weil ich dann die Ausführungszeiten besser unter Kontrolle habe. Die Zeiten sind immer recht gut vorherzusagen.
    • Ich hätte noch eine Möglichkeit, die sehr flexibel ist, dir aber trotzdem den Aufwand eines selbstprogrammierten Puffer abnimmt.
      Dies beschreibt nur den eigentlichen Empfang und das erste Verarbeiten der Zeichen.
      Du kannst natürlich auch ein eigenes Protokoll verwenden (Start-Stop-Zeichen, Checksumme usw.) oder sowas wie Mitch64 vorgeschlagen hat.

      Dazu verwendest du
      Config SerialIn = Buffered, Size=n (n so groß wie nötig, damit du kein Zeichen verpasst, auch wenn es in der Main-Loop mal länger dauert)
      In der Main-Loop verwendest du dann

      If IsCharWaiting() = 1 Then
      Rcvd_byte = Inkey() ‚abspeichern des Zeichens, evtl. direkt in ein Array oder auch schon auswerten
      End If
      Alternativ kannst du es auch so machen
      While IsCharWaiting() = 1
      'alle vorhandenen Zeichen einlesen
      Wend

      Einlesen des Zeichen aber immer mit Inkey(), weil das nur ein Byte einliest und es daher nicht zu einem Blockieren kommen kann.
      Bei der ersten Variante wird nur ein Zeichen eingelesen, auch wenn mehrere verfügbar sind.
      Wenn die Main-Loop dann einmal durch ist, kommt erst das nächste Zeichen dran.
      Bei der zweiten wird alles eingelesen und erst dann läuft die Main-Loop weiter.

      Dies hat den Vorteil, dass du recht schnelle UART ISR des Compilers für SerialIn mit Ringpuffer verwendest und das nicht selber hinbekommen musst.
      Auf der anderen Seite liest du die Zeichen nur dann ein, wenn in der Main gerade Zeit dafür ist. Die Unterbrechungen per Interrupt bleiben also relativ kurz.

      Anders als beim Bytematch kannst hier leicht darauf reagieren, wenn ein Telegramm nicht komplett übertragen wurde und das Bytematch Zeichen nicht kommt.
      Wenn die Zeit abgelaufen ist, machst du einfach ein Clear SerialIn (am besten vorher den URXC Interrupt abschalten).
      Und du löschst alle Zeichen, die du schon eingelesen hast, die aber noch nicht ein vollständiges Telegramm waren.
      Falls ich nicht irgendetwas übersehen habe scheint mir das eine sinnvolle Alternative zu Alles-Selbermachen zu sein.
    • Hallo Franz!

      Danke auch für dienen Beitrag und deine Bemühungen mit dem Beispiel :thumbsup:
      An Inspiration habe ich jetzt erstmal einiges.
      Nun muss ich aber die andere Seite der Kommunikation angehen, also den Host, der mit den ganzen ATMegas spricht.
      Mit einem Terminalprogramm wird das meiste nämlich schwer zu testen sein.

      Viele Grüße,
      Michael