Lesen aus seriellem Port
-
Hi,
in meinem Lese-Code wird das Lesen erst beendet, wenn das 0xFF Zeichen kommt.
Kann man dies ohne dieses Zeichen machen?while(1) { if(WaitCommEvent(hComm, &dwEventMask, NULL)) { /*determine how many char are in RX buffer*/ ClearCommError(hComm, p_error, &stat); inQue = stat.cbInQue; /*Read them all at once*/ ReadFile(hComm, &buffer[i], inQue, &dwRead, NULL); i += inQue; }else //Error in WaitCommEvent return(0); if(buffer[i-1] == 0xFF) break; } return(i);
-
Es hängt doch von Dir ab, wann Du die Schleife beendest.
-
Ja du hast recht, aber das Problem ist fogendes:
Wenn das Zeichen 0xFF in der Nachricht enthalten ist, und er zufällig auf dieses stößt, so bricht er ab, obwohl vielleicht noch weitere ankommen.Ist zwar in der praxis nicht vorgekommen, aber ich glaube das war nur Glück.
-
Dann muss für die Kommunikation eben ein entsprechendes Protokoll verwendet werden, dass regelt wie die Daten behandelt werden.
-
JDHawk schrieb:
Ist zwar in der praxis nicht vorgekommen, aber ich glaube das war nur Glück.
Das kommt in der Praxis vor, daß Du parasitäre Bytes empfängst. Leider.
Häufigste Ursache: Die serielle Leitung wirkt als Antenne für Störsignale.D.h. Du müßtest Deine Empfangsroutine so programmieren, daß diese unerwünschten Bytes Dein Programm nicht aus dem Ruder wirft.
Idealerweise sollten Deine Übertragungsprotokolle oder -pakete immer eine Checksumme (z.B. CRC32) enthalten, damit Du überhaupt erkennen kannst daß was faul war.
Martin
-
Ein Protokoll (auch mit CRC) hab ich schon.
Es geht hier um den empfang von Daten über die serielle Schnittstelle, über die Windows API.Meine Überlegung (siehe viele andere Seiten):
Er soll warten bis ein Zeichen im Rx Buffer ankommt,
dann die angekommenen Zeichen zählen,
dann alle auf einen Schlag aus dem Rx Buffer lesen.Nun ist es so, dass auch mal Daten ankommen die größer als der Rx Buffer sind.
In dem Fall dachte ich mir er soll das in ner Endlosschleifen machen, bis ein 0xFF Byte ankommt.Das gefällt mir halt nicht. Ich dachte vielleicht kennt jemdand eine andere Möglichkeit. (Vielleicht eine Hilfsfunktion der WinAPI oder so)
Weil über diesen Char 0xFF ists blöd. Es kann ja sein das meine Nutzdaten ein 0xFF enthalten und schon bricht er ab.
-
JDHawk schrieb:
Weil über diesen Char 0xFF ists blöd. Es kann ja sein das meine Nutzdaten ein 0xFF enthalten und schon bricht er ab.
Damit kannst Du das Verfahren mit dem Wert 0xFF als Abbruchkriterium schon mal in die Mülltonne werfen.
Bei meinen (professionellen) seriellen Kommunikationen verwende ich sowohl das "Online"-Parsing OK/nichtOK als auch die Timeout-Abbruchkriterien.
Das Online-Parsing (ich nenne das mal so) ist das Abholen bereits empfangener Bytes zu beliebigen Zeitpunkten aus dem Empfangsbuffer (bei mir in einem eigenen Thread). Und das gleichzeitige Erkennen von Protokoll-Frames in dieser Bytefolge. Wenn Erkennung und Plausibilitätscheck erfolgreich -> dann diesen Frame zur Weiterverarbeitung an Hauptthread weiterreichen. Wenn nicht erfolgreich oder Frame enthält fehlerhafte Zeichen -> den ganzen Frame verwerfen und auf das nächste gültige Frame hin abklopfen.
Mit dem Timeout-Abbruchkriterium habe ich ein relativ zuverlässiges Synchronisationshilfsmittel für das Online-Parsing (in der Größenordnung 50ms oder länger, da Windows kein Realtime-OS ist).
Was Synchronisation betrifft: Es erleichtert die Implementation eines solchen Online-Parsing ungemein, wenn die Protokolle immer mit einem definierten Zeichen beginnen z.B. '!' oder '#', damit kannst Du den Beginn eines Frames sehr leicht erkennen. (es ist klar, daß dieses Zeichen auch als Nutzdaten mitten im Frame oder als CRC-Byte vorkommen kann!)
Martin
P.S.: Frame=eine Anzahl von Bytes um ein Protokoll zu bilden, z.B. ein Frame enthält das Startbyte, ein(ige)Befehlsbyte(s), Nutzbytes und abschließend die CRC-Bytes. In der Regel befinden sich zwischen den Frames Sendepausen zwischen 2 und 100ms, um die Decodierung zu erleichtern.
-
Ja aber woher weist du wann ein Frame ende?
Oder verschickst du immer ein ganzes Frame und legst absichtlich eine Pause ein, damit er einen Timeout hervorruft?Das wäre ja möglich, das mit den Timeouts lässt sich ja in der Konfiguration der seriellen Schnittstelle einstellen.
Im eigenen Thread ist auch super, dann müsste ich mich mal mit der Thread Thematik unter Win32 einarbeiten, ich hoffe nicht so schwer, in Linux gings eigentlich total einfach.
Ich habe auch ein Frame, mit allem drum und dran. Frage zu dem Frame: Bist du da wirklich bis in die Bitgrenzen mit den Flags usw. gegangen, oder reichen Bytegrenzen? Ich habe Bytegrenzen und so ein Frame kann bei mir bis zu 128Byte groß sein. (Ja ok, das wird wahrscheinlich davon abhängen wie schnell ich die Daten brauche)
-
JDHawk schrieb:
Ja aber woher weist du wann ein Frame ende?
Oder verschickst du immer ein ganzes Frame und legst absichtlich eine Pause ein, damit er einen Timeout hervorruft?Das ist Protokolldefinitionssache. Du kannst z.B. durch relativ lange Timeouts auch ein Frame-Ende signalisieren. Das funktioniert schlecht wenn Du möglichst viele Frames pro Sekunde übertragen haben möchtest, da sonst zuviel "Funkstille" zwischen den Frames erforderlich wäre.
Sinnvoller ist es, jeder Frame hat eine definierte Länge. Ich meine nicht, jeder Frame hat eine einheitliche Länge von z.B. 32 Bytes. Das wäre natürlich auch denkbar, wenn Du nur ganz simple Funktionen implementieren möchtest. Ich dachte da mehr an definierte Längen in Abhängigkeit von der Funktion des Frames. Z.B. im Frame steht ein Befehlsbyte 0xE4, dieser steht für eine bestimmte Funktion, und das resultiert in einer Gesamtlänge von 24 Bytes. Bei einem anderen Befehlsbyte eben eine andere Länge.
Somit kannst Du die Anzahl der eintrudelnden Bytes mitzählen. In den letzten zwei Bytes (auch das ist Protokolldefinitionssache) stehen die CRC-Prüfsummen, um so auch die Korrektheit des gesamten Frames überprüfen zu können.
JDHawk schrieb:
Das wäre ja möglich, das mit den Timeouts lässt sich ja in der Konfiguration der seriellen Schnittstelle einstellen.
Ja, aber erwarte nicht von Windows, daß sich (wenn Dein Thread ein Timeout-Ereignis verarbeitet) im Empfangsbuffer nur die angekommenen Zeichen bis zum Timeout befinden! Denn durch die Trägheit (ich sage mal das so) des OS sind im Empfangsbuffer vielleicht schon die ersten Zeichen vom nächsten Frame eingetrudelt... das macht das ganze in der Tat schon ein wenig schwieriger.

JDHawk schrieb:
Frage zu dem Frame: Bist du da wirklich bis in die Bitgrenzen mit den Flags usw. gegangen, oder reichen Bytegrenzen?
Natürlich nur Bytegrenzen, denn an die Bitinformationen (gemeint sind hier Startbit, Datenbits und Stoppbits) kommst Du ja gar nicht vernünftig ran.
Ich persönlich würde Dir empfehlen, fange einfach mit einem einzigen definierten Frame mit einem definierten Inhalt an. Empfangs-Thread implementieren und die empfangenen Bytes irgendwie darstellen (Messagebox oder in Datei schreiben).
Dann Funktionserweiterung um CRC-Check, usw. Erstmal nur um das Prinzip zu verstehen.
Und dann kannst Du das ganze Konzept beliebig ausbauen, bis hin zu Busfähigkeit (mehrere Teilnehmer)
Martin
P.S.: Eine serielle Schnittstelle mit WinAPI erfordert schon einen recht hohen Programmieraufwand. Vielleicht schaust Du Dir auch die fertigen Klassen oder Libraries an? Es gibt auch Freeware, z.B. http://www.codeproject.com/system/serial.asp
-
Pardon, was Busfähigkeit (mehrere Teilnehmer) betrifft: Natürlich nicht auf RS232, sondern z.B. über Konverter auf RS485.
Martin
-
Mmacher schrieb:
Pardon, was Busfähigkeit (mehrere Teilnehmer) betrifft: Natürlich nicht auf RS232, sondern z.B. über Konverter auf RS485.
MartinIch grab das Thema nochmal aus bevor ich ein neues erstelle

Ich hab mir mit der WinAPI selber eine Schnittstelle gebaut,
(keine Ahnung was daran so schwer sein soll ;O) nur hab ich
jetzt das Problem das ich auch noch ein Startbit setzen muss,
was ja soweit ich weiß mit den fertigen Libraries auch nicht geht.
Weiß jemand wie ich so ein Startbit "hintricksen" kann?Gruß,
Max
-
Hi, bin auf groesserer Asien-Rundreise (und grad auf Phuket)...
Nein blub², Du musst Dich gar nicht um das Startbit kuemmern, das macht der UART (die Schnittstelle in den ICs) vollautomatisch.
Du musst lediglich definieren, wieviele Stoppbits (also 1, 1.5 oder 2 Stoppbits) der UART senden soll. Die Einstellungen hierzu findest Du in DCB, dort wo Du auch die Baudrate usw. einstellst (kann grad nicht nachsehen, da ich ja wie gesagt in Urlaub bin
).Martin
P.S.: Kann fast gar nicht glauben dass zuhause in Deutschland ein so kaltes Wetter herrscht