Bei mir wird jedes Telegramm mit einem CHR(13) abgeschlossen. Bei "empfindlichen" Dingen kommt auch ein Zeichen für den Beginn eines Telegramms.
Hi zusammen,
wie der Titel schon verrät habe ich ein logisches Problem beim einlesen eines Telegrammes variabler Länge. Das Telegramm läuft über eine RS485-Verbindung.
Aktuell ist es so, das ich ein Telegramm mit fixer Länge verwende. Da ich weiß wie lang das Telegramm sein muss, warte ich ab bis die notwendige Anzahl an Bytes im Eingangspuffer stehen und werte die Bytes bzw. das gesamte Telegramm dann auf einmal aus.
Ich prüfe dann ob das Telegramm für diesen Teilnehmer ist, ob die Prüfsumme passt usw. usw..
Ist es nicht für mich oder stimmt irgendwas nicht, wird es einfach verworfen.
Wie mache ich das jetzt aber, wenn ich eine variable Länge habe? Ich weiß ja nicht auf wieviele Bytes ich warten muss bis das Telegramm vollständig empfangen wurde? Lese ich zunächst nur den Telegrammkopf ein und werte diesen aus? Von dem weiß ich ja die Fixlänge. Brauche ich da dann eine eigene Prüfsumme für den Telegrammkopf? Wenn ich in dem Kopf dann schon sehe das es nicht für mich ist, dann muss ich trotzdem die Nutzdaten abwarten und verwerfen?
Aktuell soll das Telegramm so aussehen: (jeweils 1 Byte)
Zieladresse / Quelladresse / Länge der Nutzdaten / Registerzugriff / ( hier kommen jetzt die variablen Nutzdaten) / Prüfsumme
Bisher war es auch so, das ich den Telegrammkopf und die Nutzdaten in die Prüfsumme habe mit einfließen lassen. Geht das dann auch noch oder macht es keinen Sinn?
Ich hoffe Ihr könnt mir weiterhelfen. Ich stehe gerade ein wenig auf dem Schlauch.
Bei mir wird jedes Telegramm mit einem CHR(13) abgeschlossen. Bei "empfindlichen" Dingen kommt auch ein Zeichen für den Beginn eines Telegramms.
Wenn das Herz involviert ist, steht die Logik außen vor! \/
Ok,
und wie gehst du vor beim Einlesen deines Telegramms?
Hallo,
Ich habe solche Decoder immer als State-Maschine im Interrupthandler eingebaut.
Eine Prüfsumme über die beiden Adressen und die Länge ist nötig, wenn sich ein Fehler bei der Länge einschleicht, findest du das Ende nicht.
Zudem brauchst du noch eine Möglichkeit, welche eindeutig den Anfang oder das Ende markiert. Sonst kannst du den Anfang der nächsten Meldung nicht finden, wenn die Länge kaputt ist.
Möglich sind irgendwelche Statusleitungen, die Zeit, wenn sichergestellt ist, dass die minimale Zeit zwischen zwei Meldungen deutlich grösser ist als die maximale Zeit zwischen zwei Zeichen oder halt ein spezielles Zeichen, bzw. ein Escape-Kombination wenn die Protokoll binär ist.
Als Escape-Zeichen nimmt man ein Bitkombination, welche normalerweise eher selten im Datenstrom vorkommt.
Nehmen wir mal z.B. 0xAA
Als Start- oder Endmarke sendest du die Bytes 0xAA, 0xFF
Wenn 0xAA im Datenstrom vorkommt, verdoppelst du dies zu 0xAA 0xAA beim Sender.
Wenn der Empfänger 0xAA 0xAA erhält, wird das erste 0xAA entfernt und das Zweite im Buffer abgelegt.
Scheinbar programmierst du in Bascom, da kann ich dir kein Beispiel liefern, nur in C könnte ich was schreiben.
MfG Peter(TOO)
Manchmal frage ich mich, wieso meine Generation Geräte ohne Simulation entwickeln konnte?
Hallo!
Auch von mir noch ein etwas anderer Ansatz bei variabler Telegrammübertragung ebenfalls mit Start/Endbyte, bei welchem die Eindeutigkeit dieser gesichert ist. Allerdings müssen dazu mindestens die Nutzdaten und wenn benötigt (Sicherheitsstufe) die Prüfsumme codiert werden. Die Prüfsumme würde ich prinzipiell über alles, ausgenommen Start/Endbyte, nehmen.
Aufbau:
- 1. Byte Startbyte (0xAA)
- 2. Byte Sender (0xFF)
- 3. Byte Empfänger (0xF1)
- 4...18 Nutzdaten (H/L codiert)
- 0xA3 (wird zu 0x0A und 0x03)
- 0x3C (wird zu 0x03 und 0x0C)
- usw...
- 19/20. Prüfsumme XOR (0xA4 -> H/L codiert)
- 0x0A
- 0x04
- 21. Endbyte (0xBB)
Start/Endbyte sind natürlich so zu wählen, dass keine Dopplung mit den Master/Slave Adressen auftreten kann. Ist dies nicht zu realisieren, müssen diese ebenfalls codiert werden.
Das ganze kann man ebenfalls im eigenen Tread/IRQ autark laufen lassen, allerdings kann man grundsätzlich beim Empfang des Startbytes zurücksetzen und bis zum Erreichen des Endbyte einlesen, da diese eindeutig sind und nicht in den anderen Daten vorkommen können.
Nachteil ist, dass sich das Volumen der Nutzdaten/Prüfsumme erhöht und deshalb bei Volumentarifen ungünstig ist.
Somit passiert folgendes beim Empfang des obigen Beispiels:
- Startbyte 0xAA empfangen -> Reset Counter
- Bytes lessen -> Bufferspeicher (counter++)
- Byte ist Endbyte 0xBB
- Bufferspeicher auswerten
- Adressen 0xFF/0xF1 -> OK
- decodieren
- XOR über alle Byte (außer Start/Endbyte) –> vergleich mit Prüfsumme -> OK Telegramm empfangen!
Um nicht unnötig lesen zu müssen können auch unterschiedliche Start/Endbyte je Richtung festgelegt werden. Also Slave -> Master z.B. 0xAA/0xCC und Master -> Slave 0xBB/0xDD.
Für ein besseres Fehler/Wiederholungsandling kann man auch noch die Information „Anzahl der Telegramme“ und „Nummer des aktuellen Telegramms“ einbinden.
- 4. Byte Anzahl Telegramme (0x04)
- 5. byte Aktuelles Telegramm (0x02)
Könnte die Anzahl der zusammengehörigen Telegramme die Werte des Start/Endbytes erreichen müssten diese ebenfalls innerhalb der Codierung mitgeführt werden.
Und je nach Sicherheitsstufe ist es natürlich auch noch möglich die Information „Anzahl der Bytes“ innerhalb des Telegramms codiert zu hinterlegen.
Gruß André
Ich nutze immer folgendes Schema:
Code:Do If Ischarwaiting() = 1 Then Gosub Empfangen End If loop end Empfangen: B = Inkey() If B = 13 Then 'CR Gosub Auswerten Else Bb = Len(seingang) 'Noch Platz im Eingangspuffer? If Bb < 26 Then Seingang = Seingang + Chr(b) Else Seingang = "" end if End If Return Auswerten: If Len(seingang) >= 1 Then 'Überhaupt was Verwertbares? ... ... ... end if
Wenn das Herz involviert ist, steht die Logik außen vor! \/
Jo, stimmt. Binäre Daten in dem Sinne nutze ich so nicht. Da hängt das Protokoll dann vom anderen Baustein ab. Rein nach RS... werden Werte allerdings in Textform übertragen. Da braucht dann eine 200 halt 3 Bytes. Binäre Daten in dem Sinne sind dann was für 1 Wire, TWI und so. Bei komplett eigenen Projekten, wo ich beide Kommunikationspartner programmiere, wird alles so gemacht, wie ich es gepostet habe. "Binäre" Daten werden dann mit gesetztem 7.Bit übermittelt. So erkenne ich immer noch sicher den CHR(13) als Telegrammende. Bisher nur in meinem T300x Projekt (T-Hack) so gemacht.
Wenn das Herz involviert ist, steht die Logik außen vor! \/
http://de.wikipedia.org/wiki/Type-Length-Value
Am Schluss noch eine Checksum anfügen und schon hast du ein zu 99% sicheres und einfaches Protokoll.
mfg
Hallo,
ja,… das funktioniert in der Form dann auch!
Es gibt halt immer mehrere Wege zum Ziel…
Allerdings möchte ich gern noch ergänzen:
„Rein nach RS... werden Werte allerdings in Textform übertragen“…
Das würde ich nach meinen Erfahrungen nicht verallgemeinern. Ich habe mit verschiedenen Geräten zu tun, welche auf dieser Basis binär Daten übertragen und erwarten, da oft nur die elektrischen Schnittstellen aber nicht das Protokoll definiert wurde. Ein einfaches Beispiel wäre das M-Bus Protokoll, welches durch Pegelwandler auch auf RS4../RS2.. umgesetzt wird.
Bei allen wo ich wiederum Einfluss habe, nehme ich aus Gründen der Störsicherheit das komplette „Gedeck“ mit allen Sicherungen wie oben teilweise angedeutet.
Gruß André
Lesezeichen