Forum: Mikrocontroller und Digitale Elektronik Uart Protokoll entschlüsseln


von Mikrocontroller X. (kifab)


Lesenswert?

Hallo,
ich habe folgendes Problem:

Ausgangssituation:

5 ASCII Zeichen sollen seriell über das UART Protokoll in einer 
bestimmten Reihenfolge (Wert eines Sensors) von einem Mikrocontroller 
zum anderem Mikrocontroller übertragen werden. Realisiert wird dies mit 
zwei XMC2GO - Mikrocontrollern von Infineon.
Die Übertragung erfolgt durch die UART 0 - DAVE 4 - APP:

UART_Transmit(&UART_0, transmit,5); —> überträgt die ersten 5 Felder des 
Arrays „transmitt [ ]“.
UART_Receive(&UART_0, receive, 5); —> empfängt diese 5 Byte und schreibt 
sie in die ersten 5 Felder „receive []“

Wie kann ich nun sicherstellen, dass der Empfänger auch wirklich beim 
ersten Byte beginnt, die 5 Zeichen zu speichern? Z.B. wenn Sender 
beginnt zu senden, bevor Empfänger aktiv ist.

Die Methode mit einem Startbyte versuchte ich, jedoch ohne erfolg:

Ansatz war:
Sender:
Sende Startbyte z.B. 0x02
Sende die 5 Datenbyte

Empfänger:
Empfange 1 Byte
wenn Startbyte —>Empfange 5Byte—>schreibe auf LCD
wenn nicht —>Schleife von vorne

Was ich mir nicht erklären kann ist, wieso der empfangene Wert nach dem 
zweiten Empfang in der richtigen Reihenfolge abgelegt wird, obwohl 
beispielsweise durch kurzes ausstecken der TX Leitung, der erste Empfang 
noch nicht gepasst hat (verschoben war)? -->genau das will ich zwar 
erreichen, jedoch stimmt das erst beim 2. Empfang und ich weiß eben 
nicht wieso das überhaupt funktioniert.

Vielen Dank schon mal im Voraus.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Willkommen in der wunderbaren Welt des Protokolldesigns... das mit dem 
framing machst Du schon ganz richtig, wobei Du selbstverständlich darauf 
achten musst, dass das Startbyte selber niemals im Nuztdatenstrom 
vorkommen kann (da gibt es Transposition o.ä. Mechanismen).

Auf seriellen Schicht 1 Medien musst Du IMMER damit rechnen, dass 
Zeichen verloren gehen, deswegen ist ein framing unerlässlich. Wenn Du 
für alle Ewigkeiten sicherstellen kannst, dass jede Paketlänge immer 5 
ist, kannst Du es beim Startzeichen belassen, aber wenn Du nicht mit 
jedem einzelnen Byte hadern musst, ist es für Zukunftskompatibilität 
empfehlenswert, den Frame zu erweitern (also entweder Frameendzeichen 
oder - wesentlich besser - Länge im Header schicken). Eine Checksumme 
über den frame ist bei seriellen Protokollen auch kein Fehler und kann 
graue Haare vermeiden helfen.

Warum in diesem Fall erst die zweite Kommunikation hinhaut, kann man so 
aus der Ferne nicht beurteilen. Es ist nicht so etwas wie Autobauding in 
Effekt? Oder ist das zu Grunde liegende Medium vielleicht RS485 und es 
gibt Richtungsumschaltungsprobleme?

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

Fabian K. schrieb:
> Wie kann ich nun sicherstellen, dass der Empfänger auch wirklich beim
> ersten Byte beginnt, die 5 Zeichen zu speichern?

Durch Synchronisation zwischen Sender und Empfänger. Bei ASCII Zeichen 
ist das einfach, da die mit 7 Bit übertragen werden können. Indem du 
z.B. bei der Übertragung des ersten Bytes zusätzlich das achte Bit setzt 
und es beim Empfänger auswertest, läßt sich das einfach ohne 
zusätzlichen Protokoll-Overhead umsetzen.

von Olaf (Gast)


Lesenswert?

Die einfachste Moeglichkeit waere natuerlich ein Startbyte das niemals 
in deinen Nutzerdaten vorkommt. Ist aber nicht immer zu realisieren.

Naechster Ansatzpunkt, timing+Startbyte. Du kannst ja sicher davon 
ausgehen das die Zeit zwischen zwei Bytes deutlich kuerzer ist wie 
zwischen zwei Datenbloecken. Also sorge dafuer das dein Bytezaehler auf 
0 zurueckgestellt wird wenn eine zu lange Zeit vergangen ist.

Du kannst ausserdem nie sicher sein das bei einer Uebertragung ein Bit 
verfaelscht wurde. Also haenge an deine Bytes noch eine CRC16 an.

Programmiere das ganze in einer Statemachine die im Zweifel immer auf 
den Anfang zurueckfaellt. So kannst du einen stabilen Empfang 
sicherstellen der sich im Zweifel immer neu syncronisiert.

Zusaetzlich wuerde ich dir empfehlen ein Byte dafuer zu verschwenden 
einen Zaehler zu uebertragen der bei jedem Paket um eins incrementiert 
wird. So weiss der Empfaenger das er ein Paket verloren hat.

Noch sehr viel klueger waere es allerdings wenn du dir nicht selber 
etwas ausdenkt sondern ein gaengiges Protokoll verwendest. Ein Beispiel 
waere dafuer Modbus. Der Grund ist das du dann fertige Standardsoftware 
verwenden kannst um deine Uebertragung zu testen.

Olaf

von Mikrocontroller X. (kifab)


Lesenswert?

Vielen Dank schon mal für die vielen schnellen Antworten.
Da es sich nur um Zahlenwerte handelt, wäre es mit einem Startbyte 
problemlos möglich.
In dem Fall war ich also schon mal auf der richtigen Spur.
Allerdings hat das wie bereits gesagt bei meinem Versuch nicht 
funktioniert. Es kamen nur noch sehr wenige werte an und als erstes 
Zeichen wurde mir anstatt dem ersten Zahlenwert das Startbyte 
ausgegeben.Ich werde am Montag wenn ich Zeit habe meinen Code mal 
posten...

von Mikrocontroller X. (kifab)


Lesenswert?

Ich war heute noch einmal dran... Mein Fehler war, dass ich nach dem 
senden des Startbits noch ein kurzes Delay einbauen musste. Jetzt 
funktioniert es.

Ich würde jetzt jedoch vielleicht auch noch zusätzlich die 
Timing-Methode einbauen. Aber wie kann ich abfragen, wann das erste Byte 
kommt, um den Timer zu starten?

von Olaf (Gast)


Lesenswert?

> Aber wie kann ich abfragen, wann das erste Byte
> kommt, um den Timer zu starten?

Du benutzt einen Hardwaretimer der dir eine nutzbare Zeitbasis schafft. 
Ausserdem empfaengt man Bytes im IRQ.

Olaf

von Mikrocontroller X. (kifab)


Lesenswert?

Bisher habe ich ohne IRQ empfangen...
Dann versuche ich es jetzt mal mit einer IRQ, Vielen Dank.

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.