Hallo Leute! Ich sitze wieder mal über der Aufgabe eine Datenverbindung zwischen einem PC und einem uC über die RS232-Schnittstelle aufzubauen. Zum Thema Datenflussstuereung (vllt. besser: Übertragungsprotokoll aufgesetzt auf RS232)hab ich mir schon früher Gedanken gemacht und einiges mehr oder weniger erfolgreich umgesetzt. Mich würde jetzt aber interessieren wie ihr das macht und welche anderen Methoden es gibt. Um das ganze verständlicher zu machen, ein kleines Beispiel: Variablen im uC sollen durch den PC gelesen oder beschrieben werden. Folgendes Schema könnte man hier verwenden: Sende 5 Daten-Bytes über RS232: - 1 Byte: |Variablennamen+R/W| - 4 Bytes: |Daten| Der uC wartet also bis 5 Bytes eingetroffen sind und schreibt die Daten von den letzten 4 Bytes in die Variable, die durch das 1. Byte definiert wurde.(sofern "W" gesendet wurde, falls R: Sendet er den Inhalt der Variablen an PC). Das ganze ist schön und gut, nur kann es passieren, dass der uC irgendwie aus dem Tritt kommt und die falschen 5Bytes sammelt (Bytes aus zwei verschiedenen Datenströmen). Spätestens dann ist Schicht im Schacht und der uC weiß nicht mehr wo ein Paket anfängt und wo aufhört.Lösung wären natürlich Start und Stop-Zeichen. Da weiß ich nur nicht ganz, was ich da genau senden muss, damit der Datenstrom nie die selben Bits wie das Start/Stop-Zeichen enthält. Hier fehlt mir einfach die Praxis. Also nochmal zur Frage: Wie macht ihr das, welche Lösungen sind üblich? Vielen Dank! Gruß Denglmann
Ich mache gerade etwas Ahnliches mit Pick-by-Light-Empfängern: - Kommando-Byte muss ein ganz bestimmtes Bitmuster haben - dann folgen zwei Adress-Bytes - dann folgen zwei Daten-Bytes - dann folgt ein Kontroll-Byte (XOR über die vorherigen 5 Byte) Zusätzlich erfolgt die Sendung MIT Parität, nicht, wie meist üblich ohne. Jedes Kommando vom PC zum yC muss vom adressierten yC bestätigt werden. PC ist Master mit Adresse 1*, yC antwortet nur, wenn vorher gefragt ... Der yC führt Kommandos nur aus, wenn oben genannte Bedingung erfüllt. Der PC wiederholt Kommandos so lange, bis eine Bestätigung erfolgt oder nach einer eingestellten Wiederholrate der Empfänger als defekt markiert wird. Der yC prüft nach jedem eingegangenen Byte, ob obige Struktur im Puffer liegt und ob die Adresse seine eigene ist. Bei Pausen von mehr als einer Sekunde zwischen den eintreffenden Bytes wird der gesamte Puffer gelöscht. Als Bus setze ich RS485 (MAX485) im 2-Draht-Modus bei 9600 Baud ein. *Adresse Null ist reserviert für (neue) Empfänger, die sich im "Lernmodus" nach 10s langem Tastendruck befinden, um per Kommando vom PC die Adresse des Empfängers zu setzen.
@Frank Probier doch mal "Alt Gr" + "m" Dein Protokoll ist nett. Mehr auch nicht. >- Kommando-Byte muss ein ganz bestimmtes Bitmuster haben >- dann folgen zwei Adress-Bytes >- dann folgen zwei Daten-Bytes >- dann folgt ein Kontroll-Byte (XOR über die vorherigen 5 Byte) Auch ob mit oder ohne Parität ist überhaupt nicht entscheidend. Da der Beginn der Message nicht durch ein exclusives Byte repräsentiert wird, ist das "bestimmte Bitmuster" auch nur für den Decoder der Message wichtig, für die Synchronisation des Empfängers taugt es nicht. Das einzige Entscheidende ist wohl das Erkennen der Übertragungslücke zwischen den Messages und das richtige Reagieren drauf. Obs eine Sekunde sein muß, hängt doch schwer von der Aufgabenstellung ab. Ich kenn Protokolle, da gilt ein Timeout von 8 Millisekunden bei 38,4 KBaud. Da kann sich jeder Entwickler was eigenes ausdenken. Auch mit Packetwiederholung.
Ich packe das in einen Frame, ein Startbye gefolgt von den Daten, dann ein Stopbyte. Das Startbyte löscht den Empfangspuffer, wurde das Stopbyte empfangen wird der Inhalt des Empfangspuffers verarbeitet. Zu empfehlen ist noch eine Prüfsumme über den Nutzinhalt (XOR oder CRC).
Man sollte sich ein richtiges Master-Slave Protokol ausdenken. Der Controller sendet von sich aus nichts, immer nur als Antwort auf eine Anfrage. Die Anforderungen an eine Punkt zu Punkt Verbindung 1+ byte Vorspann 1 byte Datenlaenge falls variabel 1 byte Command 0+ byte Daten 2 byte CRC Dieses Paket muss innerhalb .. ms quitiert werden. Entweder mit der Antwort, oder einem Verstanden, oder einer Kopie des Commands. Datenflusskontrolle wuerd ich nicht verwenden, da die zusaetzliche Leitungen benoetigt. Eher die Baudrate genuegend langsam ansetzen, dass der Controller genuegend Zeit hat und nicht ueberflutet wird. Das Protokoll sollte zustandsfrei sein. Dh die Packete sollten unabhaengig voneinander sein, Es kann auch mal eins ausfallen.
Ich habe mal dieses Protokoll umgesetzt: http://www.ibrtses.com/embedded/shortmsgprotocol.html Ist sehr robust und kommt auch nicht aus dem Tritt, wenn ein Teilnehmer mal Käse sendet.
Es ist ganz einfach Mache ein quasi - MasterSlave-Prinzip und zwar folgendermaßen. Sende am PC Befehlswörtet beliebiger Länge und haenge am Schluss der Zeichenkette eine 13 an. (=ist Carriage Return)= <CR> Bsp: Ping<13> der µComtroller sammelt alle eintreffenden Zeichen P-i-n-g--<13> und merkt dann an der "13" AHA, hier ist das Befehlswort zu ende Schon kann man in eine Case-Liste den Befehl interpretieren. Wenn was passendes zu finden ist reagiert der µController und sendet Pong<13>. SO kann mit einem Terminal oder einer höheren Software gesteuert werden. Wenn das Befehlsformat erweitert wird, kann mit strtok eine Delimiterliste interpretiert werden. Befehl,wert1,Wert2<13> Das heist, der µController ist Passiv kann aber auch permanent selbst senden... so wie es der Entwickler will. ------------------------------- Befehlstructur typedef struct { char ucaCmd[COMAMNDSIZEMAX +1]; float fCmdVal_1; float fCmdVal_2; }COMMAND_TYPE; dann COMMAND_TYPE gsCmd; ----------------------------- Trennen der Tokens void CheckOrder(char *pcStrOrder) //von gcaRxStr { char * pStrTok; // für strtok_r char * pucCh = &pcStrOrder[ strlen(pcStrOrder) ]; strcpy(gcaStr, pcStrOrder); strcpy_P(gcaNumStr, PSTR(",")); //HILFSWEISE gcaNumStr für "," if( (pStrTok = strtok_r( pcStrOrder, gcaNumStr , &pucCh)) != NULL)//Trenne CMD, von ID, -"$$$1,CMD { strcpy(gsCmd.ucaCmd, pStrTok); } else { *gsCmd.ucaCmd = 0; }; gsCmd.ucaCmd[ COMAMNDSIZEMAX ] = 0; //Sicherheitsterminierung COMAMNDSIZEMAX=10 gsCmd.fCmdVal_1 = gsCmd.fCmdVal_2 = 0; if( (pStrTok = strtok_r( NULL, gcaNumStr, &pucCh)) != NULL)//Hole nun einen Value nach "$$$1,COMMAND,VALUE { gsCmd.fCmdVal_1 = atof(pStrTok);// Und dann TO Float }; if( (pStrTok = strtok_r( NULL, gcaNumStr, &pucCh)) != NULL)//Hole nun einen Value nach "$$$1,COMMAND,VALUE { gsCmd.fCmdVal_2 = atof(pStrTok);// Und dann TO Float }; }; --------------- Befehlsliste if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PING")) ) { Print_PStrCR( PSTR("PONG") ); return; }; -----
Denglmann schrieb: > Da weiß ich nur nicht ganz, was > ich da genau senden muss, damit der Datenstrom nie die selben Bits wie > das Start/Stop-Zeichen enthält. Das ist recht einfach. Du sendest als Steuerzeichen die "üblichen" STX (0x02) und ETX (0x03). Die Nutzdaten überträgst du aber nur mit darstellbaren Zeichen, also z.B. A-Z, a-z. Satzzeichen gehen natürlich auch. Damit kannst du ganz klar zwischen Steuerzeichen und Nutzdaten unterscheiden. Ein Nachteil der Methode ist, dass der Datendurchsatz kleiner wird da du Hexwerte erst in ASCII umwandeln mußt. Z.B. deine Variable enthält 0x26. Darus wird bei der Übertragung 0x32, 0x36. Also 2 ASCIIbytes statt einem Byte direkt aus der Variablen. Vollständig sieht das Beispiel dann so aus: <STX> <0x32><0x36><ETX> <0x02><0x32><0x36><0x03> Zurückwandeln in den Hexwert mußt du im Emfänger natürlich auch noch. Erweitern mit Prüfsummen u.s.w. geht natürlich, da sind der Fantasie keine Grenzen gesetzt. Aber auch die Prüfsumme wieder in darstellbaren ASCII-Zeichen übertragen.
Daniel V. schrieb: > Ich habe mal dieses Protokoll umgesetzt: > > http://www.ibrtses.com/embedded/shortmsgprotocol.html Ich habe nur mal kurz reingeschaut, aber wie es aussieht, ist alles außer Sync+ und STX nicht ASCII-kodiert, d.h. die Synchronisierung ist nicht eindeutig und kann schief gehen. Wenn schon, dann sollten alle Bytes ASCII-kodiert sein - natürlich geht das auf Kosten der Geschwindigkeit. Gruß Dietrich Edit: ich sehe gerade, 900ss D. ich mit zuvorgekommen ;-(
Dietrich L. schrieb: > Daniel V. schrieb: >> Ich habe mal dieses Protokoll umgesetzt: >> >> http://www.ibrtses.com/embedded/shortmsgprotocol.html > > Ich habe nur mal kurz reingeschaut, aber wie es aussieht, ist alles > außer Sync+ und STX nicht ASCII-kodiert, d.h. die Synchronisierung ist > nicht eindeutig und kann schief gehen. > Wenn schon, dann sollten alle Bytes ASCII-kodiert sein - natürlich > geht das auf Kosten der Geschwindigkeit. > > Gruß Dietrich > > Edit: ich sehe gerade, 900ss D. ich mit zuvorgekommen ;-( Im Prinzip hast du recht. Allerdings: 1.) im Header ist eindeutig definiert, wie Lange die Nachricht sein soll 2.) das Ganze schließt mit einer CRC ab 3.) Man kann auch definieren, dass das Startzeichen STX mehrmals kommen muss, bevor man einen Start der Sendung akzeptiert Falls die oben genannten Bedingungen nicht erfüllt sind, dann wird die Nachricht nicht akzeptiert. Das finde ich schon sehr sicher. Nachtrag: ASCII hat natürlich den Vorteil, dass es lesbar ist, z.B. in Hyperterminal
Daniel V. schrieb: > Das finde ich schon sehr sicher. ... was auch immer "sehr" bedeutet. Für den Heimgebrauch und bei unkritischen Anwendungen ist das vielleicht sicher genug. (Ich bin halt "verdorben": habe in der Fernwirktechnik gearbeitet, da werden mit den Telegrammen z.B. Schaltanlagen geschaltet. Im Fehlerfall ist vielleicht eine ganze Stadt dunkel...) Gruß Dietrich
>>Daniel V. schrieb: >> Das finde ich schon sehr sicher. > >... was auch immer "sehr" bedeutet. Für den Heimgebrauch und bei unkritischen Anwendungen ist das vielleicht sicher genug. Wenn keine Antwort auf das Packet kommt, ging's verloren, und wird wieder ausgesandt, resp die Antwort nochmals angefordert. Daher ist es wichtig, ohne Zustaende zu arbeiten.
Quoten bzw. escapen ist auf eine Möglichkeit, so macht es z.b. ppp.
Daniel V. schrieb: > 3.) Man kann auch definieren, dass das Startzeichen STX mehrmals kommen > muss, bevor man einen Start der Sendung akzeptiert Kann mir einer erklären, was es bringt, wenn das STX wiederholt wird?
Die Zustandsmaschine kann sicherer re-synchronisieren wenn der Header laenger ist. Mit einem laengeren Header hat man schon nach 5 Zeichen Gewissheit dass etwas nicht stimmt und kann verwerfen. An Sicherheit bezueglich den Daten gewinnt man nichts, denn der CRC faengt ein verheddertes Packet eh ab.
@Zac Hobson Bezieht sich dein Post von 19:43 auf meine Frage? Konrad S. schrieb: > Kann mir einer erklären, was es bringt, wenn das STX wiederholt wird? Dann ist mir entgangen, dass hier von synchronen Datenübertragung die Rede ist! Bei asynchroner Datenübertragung, wovon ich ausgegengen bin, bringt das Wiederholen des STX - meiner Meinung nach - nichts. Ich bin in dieser Sache einer anderen Meinung gegenüber durchaus aufgeschlossen, sofern sie gut begründet ist. (Man möge die Ausdrucksweise verzeihen. Ich hoffe, meine Skepsis ist herauszulesen.)
Hallo Die Fernwirktechnik bedient sich zweier Telegrammtypen. Telegramm mit fixer Länge (z.B, drei Datenbyte) Startbyte 0x10h 1.Datenbyte 2.Datenbyte 3.Datenbyte Checksum Stoppbyte 0x16h Telegramm variabler Länge Startbyte 0x10h Telegrammlänge Telegrammlänge Cpoy Startbyte 1.Datenbyte n.Datenbyte Checksum Stoppbyte 0x16h Nur so eine Anregung Lg. Johann K.
hallo Mir ist ein Kopiefehlere unterlaufen. Beim Telegramm mit variabler Länge ist das Startbyte nicht 0x10h sondern 0x68. lg. johann K.
>Dann ist mir entgangen, dass hier von synchronen Datenübertragung die
Rede ist!
Wir reden von einer asynchronen Uebertragung. Es geht im Wesentlichen um
die festen Zeichen eines Headers. Je mehr feste Zeichen enthalten sind,
desto eher merkt der Empfaenger wenn etwas nicht stimmt.
Der Empfaenger hat eine Zustandsmaschine mitlaufen, die vergleicht, was
wann kommen muss. Wenn der Header schon nicht stimmt, kann er schneller
neu synchronisierenm als wenn er's erst beim CRC merkt.
Der Ansatz mit mehreren SYN zu beginn weg ist daher gut.
Zac Hobson schrieb: > Der Ansatz mit mehreren SYN zu beginn weg ist daher gut. Du gestattest, dass man anderer Meinung ist. IMHO ist alles, was nicht dafür sorgt, dass das Synchronisierbyte nicht in den Daten vorkommen kann, Müll. Diverse Spielchen mit: Wir wissen wie lang der Header maximal ist, Timeout und sonstiges sind alles Krücken, um das eigentlich Problem zu verschleiern oder so zu verstecken, dass unerfahrene Programmierer nur nicht bemerken, dass es hier eine potentielle Fehlerquelle gibt. Das Synchroniserbyte muss EINDEUTIG aus dem Datenstrom identifizierbar sein. Und das ist gar nicht mal so schwer zu erreichen. Das Stichwort Escapen ist ja schon gefallen. Und dann braucht man auch nur genau 1 Synchronisierbyte und nicht mehr.
Ah, ja, wenn ich genügend "Synchronisationsbytes" übertrage, tritt irgendwann ein Übertragungsfehler auf, den ich Empfänger dann erkennen kann, ist klar. Soll ich jetzt mit Übertragungsfehlern morsen, oder was? Je weniger Bytes übertragen werden, desto weniger "Platz" ist für Fehler! Gegen welche Art von Übertragungsfehlern soll das Verfahren denn helfen?
Konrad S. schrieb: > Ah, ja, wenn ich genügend "Synchronisationsbytes" übertrage, tritt > irgendwann ein Übertragungsfehler auf, den ich Empfänger dann erkennen > kann, ist klar. Soll ich jetzt mit Übertragungsfehlern morsen, oder was? > Je weniger Bytes übertragen werden, desto weniger "Platz" ist für > Fehler! > Gegen welche Art von Übertragungsfehlern soll das Verfahren denn helfen? Übertragungsfehler werden nicht verbessert. Lediglich das Aufsetzen auf den Anfang. Das Ursprungsgegenargument war, dass in meinem verlinkten Protokoll nicht eindeutig klar ist, ob SYN einen Anfang des Telegrams markiert oder nicht. Das kann man dadurch verbessern, dass man definiert, dass das Telegram generell mit z.B. 4x SYN beginnt, also: <SYN><SYN><SYN><SYN><..>. Die Wahrscheinlichkeit, dass im Datenstrom 4 mal SYN hintereinander kommt ist geringer, als dass es 1 mal vorkommt. Übertraungssicherheit gewinnt man dadurch nicht.
Nachtrag: An meinem verlinkten Prokoll finde ich z.B. gut, dass man nicht unbedingt in ASCCII senden muss, sondern auch Binärdaten übertragen kann. Der Dateninhalt wird über das Befehlsbyte definiert. Karl-Heinz hat davon gesprochen, das TimeOut eine Krücke ist. Richtig, wenn ich sage, dass nach einer bestimmten Zeit das Telegramm zu Ende ist. Im beschriebenen Protokoll ist das aber nicht der Fall. Im Header steht drin, wie Lange die Nachricht ist. Insofern zähle ich einfach die einkommenden Bytes durch. Wenn dann das Telegramm stimmig ist (CRC), kann ich es verarbeiten. Theoretisch kann sogar ohne Pause das nächste Telegramm eintrudeln.
Daniel V. schrieb: > Die Wahrscheinlichkeit, dass im Datenstrom 4 mal SYN hintereinander > kommt ist geringer, als dass es 1 mal vorkommt. Wenn die Daten geeignet escapet sind, dann kommt SYN bzw. STX (oder was auch immer) im Datenstrom garantiert nicht vor und das STX signalisiert den Beginn der Nachricht. Den Quatsch mit SYN kann man sich dann auch sparen. Eine Absicherung gegen Übertragungsfehler, z.B. durch CRC, ist natürlich immer noch sinnvoll. Wer mit AVRs arbeitet, dem sei der Abschnitt "Multi-processor communication mode" bei der UART/USART-Beschreibung ans Herz gelegt. Man spart sich das escapen, kann alle Byte-Werte übertragen und die Adressierung ist gleichzeitig der Beginn einer Nachricht. OK, es kostet ein Bit pro Byte mehr an Übertragungsbandbreite.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.