Forum: Mikrocontroller und Digitale Elektronik Messwerte per RS232 übertragen


von Andi K. (fry12)


Lesenswert?

Hallo!

Ich möchte über die serielle Schnittstelle (eigentlich USB CDC) 
Sensordaten an den PC übertragen. Damit die Daten auch den 
entsprechenden Sensoren zugeordnet und die einzelnen Messwerte 
voneinander unterschieden werden können, brauche ich ein kleines 
"Protkoll". Der PC initiiert das Senden der Daten, ab da werden 
kontinuerlich mehrere Pakete mit Messwerten hintereinander geschickt.

Dazu habe ich mir folgende Überlegungen gemacht:
* Der Beginn einer Übertragung muss durch ein spezielles Byte 
gekennzeichnet werden (ich habe mich willkürlich für STX = 0x2 
entschieden)
* Die Messwerte selbst müssen durch ein spezielles Byte voneinander 
getrennt werden werden (z.B. ';' = 0x3B)
* Und jetzt das große Aber: Die Daten müssen aus Leistungsgründen binär 
und nicht ASCII-codiert übertragen werden

Dabei ergibt sich jetzt natürlich ein Problem: Was passiert wenn die 
beiden Steuerungsbytes STX und ';' in den Nutzdaten selbst vorkommen? 
Ein anscheinend gängiger Ansatz ist es, die Steuerungsbytes zu 
wiederholen, falls sie in den Daten selbst stehen, also bspw.:

...';'0x02';'... wird zu ...';'0x02 0x02';'...

Sobald also 0x02 gelesen wird, kannn es sich entweder um den Anfang 
einer Übertragung handeln oder um Nutzdaten. Das wird dann durch das 
nächste Byte entschieden.

Habe ich jetzt aber ';'0x3B';' wird daraus ein ';'0x3B 0x3B';', d.h. 
effektiv habe ich dann viermal 0x3B hintereinander stehen und so langsam 
kann nichts mehr voneinander unterschieden werden. Außerdem kommt hinzu, 
dass jeweils ein Messwert aus 16 Bit besteht, d.h. im worst case Fall 
würde ich ein 0x3B 0x3B 0x3B 0x3B 0x3B 03xB empfangen, aus dem nun 
wirklich nur sehr schwer etwas zu extrahieren ist.

Ich habe selbst wenig Erfahrung mit serieller Datenübertragung (bisher 
nur als ASCII), daher frage ich hier im Forum:

Welche Möglichkeiten gibt es, Binärdaten per serieller Schnittstelle 
sauber zu übertragen? Oder ist mein Ansatz nicht völlig verkehrt und 
braucht nur ein paar Änderungen?

Vielen Dank an die Experten ;)

von Blackbird (Gast)


Lesenswert?

HDLC?
Aber großer Aufwand.

Blackbird

von dummschwaetzer (Gast)


Lesenswert?

du nummerierst die sensoren,
sendest 0x02 Nummer.
Sensor Antwortet
Nummer Daten1 Daten2 CRC.
Da du eine feste länge hast kannst du auf das 0x3B verzichten.

von oldmax (Gast)


Lesenswert?

Hi
Wie ist es mit fester Blocklänge der Daten ? Und nun die rein 
provokatorische Frage: meinst du, wenn du ASCII-Daten überträgst, am 
Empfänger entsprechend 30h abziehst dund dann die so ermittelte Zahl der 
Stelle zuordnest, das dies soviel Zeit erfordert? Zumindest ist alles 
>47 und kleiner 58 eine Zahl (2Fh und 3Ah).
Gruß oldmax

von Conny G. (conny_g)


Lesenswert?

Was Du meinst nennt sich "maskieren" oder englisch "escaping".

http://en.wikipedia.org/wiki/Escape_character

Das kannst Du eigentlich mit beliebigen Zeichen machen, es muss nur in 
beide Richtungen funktionieren.
Man kann mit dem Escape Zeichen nur eines maskieren oder beliebige 
Steuerzeichen.
Du kannst auch den Backslash verwenden, wie es gerne gemacht wird.

Man benutzt immer ein bestimmtes Zeichen um die Maskierung einzuleiten.
Kommt danach nochmal dieses Zeichen, dann ist dieses gemeint (\\ = \ 
oder wie bei Dir 0x3B0x3B = 0x3B).
Jedes andere Zeichen danach ist ein Steuerzeichen.

Also:
0x02  = Steuerzeichen Anfang
\0x02 = Daten
0x3B  = Trennzeichen
\0x3B = Daten
\\    = \

Es ist egal wie oft hintereinander das in den Daten dann vorkommt.
Bei der Dekodierung geht es einfach immer rückwärts nach diesem Prinzip.

Schau dir mal diese Software und dieses Protokoll zur Übertragung der 
Messwerte an:
http://www.serialcominstruments.com/SerialComInstruments%20Doku.pdf
Beitrag "Projekt: Virtuelle Instrumente an serielle Schnittstelle"

von Karl H. (kbuchegg)


Lesenswert?

Andi K. schrieb:

> kann nichts mehr voneinander unterschieden werden. Außerdem kommt hinzu,
> dass jeweils ein Messwert aus 16 Bit besteht


... was aber auch der Empfänger weiss.
D.h. du weisst, dass nach einem 0x02 jeweils 2 Bytes (mit dem Sonderfall 
eines 0x02 Datenbytes) zusammengehören. Wodurch die Notwendigkeit eines 
Trenn-'Zeichens' nicht mehr gegeben ist. Du brauchst es schlicht und 
ergreifend nicht.

von Thomas E. (thomase)


Lesenswert?

Andi K. schrieb:
> * Und jetzt das große Aber: Die Daten müssen aus Leistungsgründen binär
> und nicht ASCII-codiert übertragen werden

Von welcher Hochleistungsanwendung redest du hier, wenn du an dieser
Stelle...

Andi K. schrieb:
> dass jeweils ein Messwert aus 16 Bit besteht

...nicht 4 statt 2 Bytes übertragen kannst?

Du kanst deine Messwerte aber auch im Block übertragen:

Preambel
MW0
MW1
...
MWn
Postambel

Dann ergibt sich aus der Reihenfolge die Zuordnung. Sodass die 
Zusatzzeichen nicht vor und nach jedem Messwert gesendet werden müssen.

Zwischen den Ambeln kannst du auch Binärdaten senden, musst dem PC aber 
beibringen, dass er dann nicht darauf triggern darf. Wenn jetzt 
allerdings einer das Kabel zieht, hängt die Kiste. Einem sicheren 
Protokoll darf das aber nichts ausmachen.

mfg.

von Andi K. (fry12)


Lesenswert?

oldmax schrieb:
> Hi
> Wie ist es mit fester Blocklänge der Daten ? Und nun die rein
> provokatorische Frage: meinst du, wenn du ASCII-Daten überträgst, am
> Empfänger entsprechend 30h abziehst dund dann die so ermittelte Zahl der
> Stelle zuordnest, das dies soviel Zeit erfordert? Zumindest ist alles
>>47 und kleiner 58 eine Zahl (2Fh und 3Ah).
> Gruß oldmax

Ich sende pro "Paket" netto (also ohne Kontrollbytes) sechs 16 Bit 
Werte. Wenn ich jetzt bspw. sechs mal 65536 schicken muss, bekomme ich 
bei ASCII 6 * 5 = 30 bytes anstatt 12 bytes. Das fällt dann bei vielen 
Sensoren (> 50) durchaus etwas ins Gewicht.

dummschwaetzer schrieb:
> du nummerierst die sensoren,
> sendest 0x02 Nummer.
> Sensor Antwortet
> Nummer Daten1 Daten2 CRC.
> Da du eine feste länge hast kannst du auf das 0x3B verzichten.

Okay, also ist in diesem Fall ein "richtiges" Protokoll besser geeignet 
als meine recht einseitige Lösung. Eine feste Blocklänge wäre wohl 
wirklich am Besten.

von Michael S. (schiko)


Lesenswert?

Start- oder Endbyte(s), das nicht im Datenstrom vorkommt,
Dahinter ev. Checksumme
Dh. nur 255 statt 256 Werte möglich je Daten-Byte,
das sollte selten nicht verkraftbar sein
Statt Messwerte per Separator zu trennen, ein Header-Byte spendieren,
wenn sich die Anzahl der Sensoren denn unbedingt ändern können muss.

von Karl H. (kbuchegg)


Lesenswert?

Andi K. schrieb:

> Ich sende pro "Paket" netto (also ohne Kontrollbytes) sechs 16 Bit
> Werte. Wenn ich jetzt bspw. sechs mal 65536 schicken muss, bekomme ich
> bei ASCII 6 * 5 = 30 bytes anstatt 12 bytes. Das fällt dann bei vielen
> Sensoren (> 50) durchaus etwas ins Gewicht.

Die Frage ist aber: Stört dich das technisch gesehen?
Welche Update-Rate kriegst du damit hin und reicht diese Rate oder ist 
es zu wenig?

Das ist der entscheidende Punkt. Es gibt da einen 'Sager': man muss 
nicht maximal schnell sein. Man muss nur schnell genug sein.

von Andi K. (fry12)


Lesenswert?

Karl Heinz schrieb:
> Andi K. schrieb:
>
>> Ich sende pro "Paket" netto (also ohne Kontrollbytes) sechs 16 Bit
>> Werte. Wenn ich jetzt bspw. sechs mal 65536 schicken muss, bekomme ich
>> bei ASCII 6 * 5 = 30 bytes anstatt 12 bytes. Das fällt dann bei vielen
>> Sensoren (> 50) durchaus etwas ins Gewicht.
>
> Die Frage ist aber: Stört dich das technisch gesehen?
> Welche Update-Rate kriegst du damit hin und reicht diese Rate oder ist
> es zu wenig?
>
> Das ist der entscheidende Punkt. Es gibt da einen 'Sager': man muss
> nicht maximal schnell sein. Man muss nur schnell genug sein.

Leider komm ich da schnell an eine Grenze. Geplant sind 64 Sensoren, die 
alle 2 ms Messwerte ausspucken. Da komme ich dann auf netto 937,5 
kbyte/s. Der Controller hat USB Full Speed (12 Mbit/s), aber davon 
bleiben (gemessen) maximal 960 kbyte/s übrig.

von Thomas E. (thomase)


Lesenswert?

Andi K. schrieb:
> Ich sende pro "Paket" netto (also ohne Kontrollbytes) sechs 16 Bit
> Werte. Wenn ich jetzt bspw. sechs mal 65536 schicken muss

Der höchste Wert bei 16 Bit 65535, 65336 sind schon 17 Bit.

Zweitens sendet man keine Dezimal- sondern Hexadezimalzahlen.

mfg.

von Andi K. (fry12)


Lesenswert?

Thomas Eckmann schrieb:
> Zweitens sendet man keine Dezimal- sondern Hexadezimalzahlen.

Da war ich gerade auf dem falschen Dampfer, sorry. Du meinst, dass man 
beispielsweise 9247 = 0x241F als 0x2 0x4 0x1 0xF sendet und dadurch zwar 
die doppelte Byte-Zahl hat, aber nur 16 ASCII Zeichen belegt sind und 
andere als Steuerungsbytes verwendet werden können? Habe ich das richtig 
verstanden?

von Der Rächer der Transistormorde (Gast)


Lesenswert?

Andi K. schrieb:
> Welche Möglichkeiten gibt es, Binärdaten per serieller Schnittstelle
> sauber zu übertragen?

Keine. In einem Datenstrom der mit möglichst hoher Geschwindigkeit 
laufen soll und in dem alle Bits irgendwann mal vorkommen hast du keine 
Möglichkeit Anfang und Ende zu synchronisieren.

Bei USB CDC kannst du auch kein Zeittelegramm erstellen da die 
Übertragung zeitlich von der USB Konfiguration abhängt (z.B. welche und 
wie viele USB Geräte am Bus hängen).


Da hast aber Messwerte. Da würde ich jetzt einfach einen verbieten (z.B. 
das Sync Muster hex 5A = 01011010) und als Start Byte nehmen. Kommt das 
dann 2 mal hintereinander ist es eben ein Datenbyte.

Es gibt dann natürlich den Fall das in den Daten das Sync Muster 
mehrmals vorkommt (oder nur noch mit der chance von 1/255). Das fängst 
du ab indem du vereinbarst das mehr als zwei Syncs hintereinander 
gültige Daten sind und Sync jetzt $A5 ist. So lange bis wieder nur ein 
einzelnes (oder eine ungerade Anzahl) $5A kommt.

Eine Prüfsumme kann man da auch noch dranhängen. Die ID des Datenkanals 
ist die Position des Wertes im Datenstrom zwischen den Syncs.

Wie viele Datenpaare bis zu einem Sync übertragen werden legst du selbst 
fest.

von Karl H. (kbuchegg)


Lesenswert?

Andi K. schrieb:

>> Das ist der entscheidende Punkt. Es gibt da einen 'Sager': man muss
>> nicht maximal schnell sein. Man muss nur schnell genug sein.
>
> Leider komm ich da schnell an eine Grenze. Geplant sind 64 Sensoren, die
> alle 2 ms Messwerte ausspucken.

ok. das ist der Plan.
Die nächste Frage lautet: gibt es für die 2ms einen bestimmten Grund 
oder sind die per Bauchegfühl festgelegt worden? (Nicht lachen: Kommt 
häufiger vor als man denkt).

Lautet die Antwort: die 2ms sind recht willkürlich festgelegt worden, 
weil der Designer immer erst mal 2 Millisekunden nimmt.
dann kann man die 2ms ja auch mal in Frage stellen. Ein Mensch wird 
sicherlich nicht 500 Messwerte pro Sekunde mit seinem Gehirn verarbeiten 
können. Temperaturen ändern sich im Regelfall nicht so schnell, dass es 
eine Rolle spielt, ob man Temperaturwerte 500 mal pro Sekunde updated, 
oder doch nur 100 mal. Ein Motor (überhaupt wenn er ein Schwungrad hat) 
ändert seine Drehzahl nicht wesentlich in 2ms. Überhaupt haben 
mechanische Systeme eine gewisse Trägheit inne, die oft eine hohe 
Updaterate zur reinen Zahlenakrobatik degradieren.

Sind die 2ms aber unabdingbar, weil zb eine Regelschleife die so 
braucht, dann geht da logischerweise nichts mehr.

von Der Rächer der Transistormorde (Gast)


Lesenswert?

Andi K. schrieb:
> Leider komm ich da schnell an eine Grenze. Geplant sind 64 Sensoren, die
> alle 2 ms Messwerte ausspucken.

Dann nimm doch einfach 2 Controller. Das kannst du später auch beliebig 
erweitern oder mit der Datenrate runter gehen.

von Thomas E. (thomase)


Lesenswert?

Andi K. schrieb:
> Habe ich das richtig
> verstanden?
Ja.

Andi K. schrieb:
> Leider komm ich da schnell an eine Grenze. Geplant sind 64 Sensoren, die
> alle 2 ms Messwerte ausspucken. Da komme ich dann auf netto 937,5
> kbyte/s. Der Controller hat USB Full Speed (12 Mbit/s), aber davon
> bleiben (gemessen) maximal 960 kbyte/s übrig.

Das ist mir aber nicht ganz klar.

16 Bit Messwert = 4 ASCII-Zeichen.

64 * 4 / 2ms = 128K/s

Karl Heinz schrieb:
> Sind die 2ms aber unabdingbar, weil zb eine Regelschleife die so
> braucht, dann geht da logischerweise nichts mehr.

Damit wäre das Unechtzeitsystem PC aber ohnehin überfordert.

mfg.

von Der Rächer der Transistormorde (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> 64 * 4 / 2ms = 128K/s

64 Sensoren * 4 Byte / 2ms = 128K/s??


Es sind nicht 128K sondern 128 kB(yte)

RS232 hat aber incl. Start und Stop 10 bit pro Byte.

von Andi K. (fry12)


Lesenswert?

Thomas Eckmann schrieb:
> Andi K. schrieb:
>> Leider komm ich da schnell an eine Grenze. Geplant sind 64 Sensoren, die
>> alle 2 ms Messwerte ausspucken. Da komme ich dann auf netto 937,5
>> kbyte/s. Der Controller hat USB Full Speed (12 Mbit/s), aber davon
>> bleiben (gemessen) maximal 960 kbyte/s übrig.
>
> Das ist mir aber nicht ganz klar.

Der Post war ja auch vor meiner Nachricht, dass ich das missverstanden 
habe ;)

Wie gesagt, es sind sechs Messwerte, deswegen nochmal neu gerechnet:
(64 Sensoren*6 Messwerte*4 Byte) / 2 ms = 750 kbyte/s Netto-Datenrate.

Ich werd mir den Ansatz mal genauer anschauen, vielen Dank schon mal!

von Thomas E. (thomase)


Lesenswert?

Der Rächer der Transistormorde schrieb:
> Es sind nicht 128K sondern 128 kB(yte)
Nein, nein. Bei 128 Kelvin geht der UART in Supraleitung und schafft die 
Übertragung schneller.

Der Rächer der Transistormorde schrieb:
> RS232 hat aber incl. Start und Stop 10 bit pro Byte.
Hat, nicht hat aber.

mfg.

von Thomas E. (thomase)


Lesenswert?

Andi K. schrieb:
> Wie gesagt, es sind sechs Messwerte, deswegen nochmal neu gerechnet:
> (64 Sensoren*6 Messwerte*4 Byte) / 2 ms = 750 kbyte/s Netto-Datenrate.

Alles klar. 6 Messwerte vom Sensor. Das war mit entgangen.

mfg.

von Statler (Gast)


Lesenswert?

Ohne mich in eure Zeitberechnungen einmischen zu wollen: Das Problem der 
Unterscheidung Steuerung/Daten kenne ich auch. Ich löse es gerne indem 
ich mich an CAN "anlehne". Die Werte 00h bis 1Fh sind auf dem Bus immer 
Steuerbytes. Das Steuerzeichen 0Ah übernimmt dann die "Shift"-Funktion. 
Wenn ein Messwert kleiner 20h ist, wird ihm der Shift-Befehl 
vorangestellt und der Wert selbst dann um 20h erhöht. Der Empfänger kann 
es dann wieder "on-the-fly" entsprechend zurücknehmen.

Also z.B. aus Messwert "05h" wird "0Ah 25h". Der Empfänger weiss dann, 
dem nächsten Zeichen werden die entsprechenden MSB maskiert und als Data 
gewertet. Ein Nachteil bleibt natürlich bei vielen kleinen Werten...

von Der Rächer der Transistormorde (Gast)


Lesenswert?

Andi K. schrieb:
> 750 kbyte/s Netto-Datenrate

1 Byte sind 8 bit. USB ist ein serieller Bus der nur ein Bit zur Zeit 
überträgt. Deshalb ist die Datenrate auch in Bit angegeben, Bei USB high 
speed 12 Mbit.

Das ist aber die Bruttorate eher Marketing. Es gibt jede Menge Protokoll 
Overhead, Prüfsummen und auch noch Latenzzeiten.

Davon kann CDC wieder nur einen Teil, hab aber selber nie mehr als 115k 
gemacht.

USB ist auch nicht echtzeitfähig, da wg. der wechselnden hierarchische 
Topologie nun mal keine garantierten Antwortzeiten ermittelt werden 
können.

Thomas Eckmann schrieb:
> Nein, nein. Bei 128 Kelvin geht der UART in Supraleitung und schafft die
> Übertragung schneller.
>
> Der Rächer der Transistormorde schrieb:
>> RS232 hat aber incl. Start und Stop 10 bit pro Byte.
> Hat, nicht hat aber.

Verstehe ich nicht.

von Andi K. (fry12)


Lesenswert?

Der Rächer der Transistormorde schrieb:
> 1 Byte sind 8 bit. USB ist ein serieller Bus der nur ein Bit zur Zeit
> überträgt. Deshalb ist die Datenrate auch in Bit angegeben, Bei USB high
> speed 12 Mbit.
>
> Das ist aber die Bruttorate eher Marketing. Es gibt jede Menge Protokoll
> Overhead, Prüfsummen und auch noch Latenzzeiten.
>
> Davon kann CDC wieder nur einen Teil, hab aber selber nie mehr als 115k
> gemacht.

Das ist alles schön und gut, aber ich habe mit dem Controller die 
maximal mögliche Datenrate über USB CDC mehrfach gemessen und komme auf 
960kbyte/s, also dürften 750kbyte/s vielleicht drin sein. Das hat sich 
auch mit den Aussagen auf anderen Websites gedeckt, dass 6-8 Mbit/s bei 
USB Full Speed (High Speed ist wieder etwas anderes) mit CDC durchaus 
möglich sind.

Statler schrieb:
> Ohne mich in eure Zeitberechnungen einmischen zu wollen: Das Problem der
> Unterscheidung Steuerung/Daten kenne ich auch. Ich löse es gerne indem
> ich mich an CAN "anlehne". Die Werte 00h bis 1Fh sind auf dem Bus immer
> Steuerbytes. Das Steuerzeichen 0Ah übernimmt dann die "Shift"-Funktion.
> Wenn ein Messwert kleiner 20h ist, wird ihm der Shift-Befehl
> vorangestellt und der Wert selbst dann um 20h erhöht. Der Empfänger kann
> es dann wieder "on-the-fly" entsprechend zurücknehmen.
>
> Also z.B. aus Messwert "05h" wird "0Ah 25h". Der Empfänger weiss dann,
> dem nächsten Zeichen werden die entsprechenden MSB maskiert und als Data
> gewertet. Ein Nachteil bleibt natürlich bei vielen kleinen Werten...

Danke für deine Antwort, dein Ansatz hört sich auch nicht schlecht an! 
Wie gehst du dann mit der variablen Länge der Übertragungspakete um?

von Statler (Gast)


Lesenswert?

Die Paketlänge ist damit ganz egal, da Control (00h bis 1Fh) und Data 
sauber auseinander gehalten werden kann. Ich arbeite aber dann auch 
gerne mit den definierten ASCII-Steuerzeichen, also SOH, STX, EOT etc.

Also in deinem Fall z.B.:
STX-[addr]-[data_0..n]-ETX

Wenn Adresse>63 dann vielleicht:
STX-[addr_0]-[addr_1]-[data_0..n]-ETX

oder:
SOH-[addr_0..n]-STX-[data_0..n]-EOT

Um den "Shift"-Fall zu reduzieren, könnte man auch die Controlbytes auf 
00h bis 0Fh reduzieren und dann die Daten nur mit 01h shiften. Aber für 
mich war's mit 32 optionalen Befehlen immer optimal.

von oldmax (Gast)


Lesenswert?

Hi
Einmal meld ich mich noch:
Wenn du dein Programm auf eine feste Übertragungslänge einstellst, hast 
du immer 50 Werte bzw. 100 Byte Nutzdaten.
Wenn du ASCII überträgst, kannst du den Transfer einleiten, wenn eine 
Änderung eintritt. Ich weiß nicht, wie dynamisch deine Werte sind, 
aberes ist alles eine Frage der Anwendung. Natürlich sind 100 Byte 
weniger wie 250, aberes kann genau so sein, das 36 Werte eigentlich ohne 
Änderung mitgeliefert werden. Dann ist das auch "Zeitverschwendung".
Das du ein Telegramm mit fester Länge schicken kannst hab ich auch 
gleich als erstes genannt.
Gruß oldmax

von TomA (Gast)


Lesenswert?

Hallo Andi,

ich möchte mich in die Diskussion über das geeignetste Protokoll nicht 
einmischen, aber ein paar Worte zur Performence von USB beitragen, 
welche ich bislang nicht gelesen habe.

Bei USB werden Daten in Packeten fester Länge übertragen. Die Länge der 
Packete wird von der Länge des Puffers eines Endpoints bestimmt und in 
einem Konfigurator festgelegt. Typische Packetlängen sind 8, 16, 32 oder 
64-Byte, für mehr Daten werden dann mehrere Packete verschickt.

Benutzt du nun ein Gerät mit einer Packetlänge von 32-Byte zum Transfer 
von 33-Byte, werden zwei Packete geschnürt. Im ersten Packet liegen 
32-Datenbyte, im zweiten Packet liegt 1-Datenbyte und 31-Füllbytes. Ob 
dies bei CDC auch so ist, habe ich nicht überprüft, gehe aber davon aus.

Die verwendete Packetgröße läßt sich mit einem USB-Sniffer feststellen, 
dann kannst du die Packetgröße deines Protokolls, ähnlich wie von oldmax 
bereits vorgeschlagen, an die Größe der USB-Packete anpassen.

Gruß. Tom

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.