Hallo,
ich möchte gerade ein kleines Programm schreiben mit welchem ich an
meinen µC eine 5 Byte lange Anfrage senden kann, darauf hin erwarte ich
eine 5 Byte lange Antwort.
ich verwende den DataReceived-Event und hier liegt vermutlich das
Problem. nach dem Senden bekomme ich das gespiegelte Telegramm nochmal
zurück (callback), anschließend sollte die Antwort vom µC kommen.
Entsprechend wird der DataReceived-Event 2x augerufen.
Lese ich hier nun die BytesToRead aus, so sollte ich beides mal 5 Bytes
erhalten. Gelegentlich bekomme ich aber 3+7 oder 4+6.
Ich warte nun im DataReceived-Event bis beide Events getriggert wurden
und schreibe alles in einen 10 Byte großen Empfangsbuffer, anschließend
lösche ich die ersten 5 Bytes.
Dies geht nun schon besser, aber auch hier läuft es irgendwann mal
schief, dann bekomme ich keine 10 Bytes mehr sondern nur 9 oder 11...
Weiß jemand warum das so ist, ich sehe keine Grund warum Windowas ausser
tritt kommen sollte :-(
Initialisierung
Gero schrieb:> ich sehe keine Grund warum Windowas ausser> tritt kommen sollte :-(
Umgekehrt stellt sich die Frage: woher soll Windows (oder jeder andere
UART unter jedem anderen BS) wissen, welche 5 Bytes eine Message bilden?
Dafür gibt es nur 2 Möglichkeiten:
A es gibt ein eindeutiges Message-End-Zeichen, z.B. CR.
B die Pause zwischen Messages ist so gross, dass man einen
entsprechenden Timeout-Wert setzen kann.
Sonst ist alles bloss ein Zeichenmatsch. Notfalls könntest du Timeout
nach 10 Bytes verwenden.
Gruss Reinhard
int i = serialPort.BytesToRead;
WriteLogFenster(i.ToString());
byte[] rx = new byte[10];
serialPort.Read(rx, 0, 10);
wenn nur i zeichen da sind, kannst du nicht einfach 10zeichen lesen.
Im DataReceived sollte man nur genau serialPort.BytesToRead zeichen
lesen nicht mehr und auch nicht weniger.
Ob deine nachricht damit komplett ist musst du duch eigenen code
feststellen.
ja das ganze geht per timeout, ich klicke manuell auf buttons, dass sind
dann mindestens 1 Sekunde zwischen den Nachrichten.
ich habe jetzt auch mal einen timer laufen lassen. Die ReadTimeout habe
ich hierbei auf 200ms gesetzt und der timmer frägt alle 1000ms einen
parameter an, selbst hier läuft das ganze nach spätestens 10 Lesezyklen
ausser Tritt.
wenn ich jede Sekunden einen Parameter anfrage und die Übertragung bei
9600baud nicht einmal 20ms dauert, müsste das doch funktionieren!
Gero schrieb:> ich habe jetzt auch mal einen timer laufen lassen.
Wo? Du musst den Tiemout für die serielle Schnittstelle setzen.
The SetCommTimeouts function and the COMMTIMEOUTS structure that are
supported by the Windows Base Services in the Windows SDK.
Gruss Reinhard
ja, das habe ich verstanden.
Hätte ich wohl besser erklären sollen, also der Timeout steht auf 200ms.
Der timer triggert alle 1000ms eine neue Anfrage an.
so sieht es auf dem Oszi aus:
¯¯¯¯¯¯¯||-||----¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯||-||----¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯||-||---¯
¯¯¯
-Frei--Tx-Rx--- Frei
|-100ms-|-------900ms------|
Gero schrieb:> Hätte ich wohl besser erklären sollen, also der Timeout steht auf 200ms.
Dann musst du nur noch dafür sorgen, dass die Timeoutzeit zu laufen
beginnt, wenn du die Abfrage startest, dann sind 200ms aber vielleicht
knapp, oder wenn das Senden fertig ist.
Übrigens gibt es mehrere Timeouts - gemeint ist die maximale Zeit
zwischen 2 Bytes.
Gruss Reinhard
Ich würde Protokolle die irgendwo auf Timing beruhen lieber sein lassen,
sofern das nicht unbedingt nötig ist.
<STX><MSG-ID><PAYLOAD-LENGTH><PAYLOAD><CRC><ETX> (oder ne Teilmenge
davon) funktioniert immer ganz gut.
nochmal hallo!
ein eindeutiges Endzeichen habe ich leider nicht
in den 5 Bytes ist ein 3 Byte Wert enthalten welcher von 0x00 bis
0xffffff jeden Wert annehmen kann. somit fällt die Reservierung für ein
Endzeichen flach :-(
Ich verstehe aber nicht wieso ich zu doof dazu bin exakt 5 Bytes
einzulesen, ich versuche es jetzt mal ohne Event sondern einfach senden
und dann 100ms warte bis ich den buffer wieder auslese.
Die sendPort kann ich wohl nicht so konfigurieren dass die gesendeten
Daten nochmals im Rx-Buffer landen, oder?
so, nochmal ich :-)
wenn ich es wie eben beschrieben mache, funktioniert es!
Ich verzichte jetzt auf den Event und gehe stattdessen nach dem senden
in einen Thread.Sleep(100), dannach lese ich den Buffer aus.
Schade dass das mit dem Event nicht klappt, ich habe aber gestern noch
ewig mit den Timoutzeiten hin und her gemacht und bin zu keinem
zufriedenstellendem Ergebniss gekommen :-(
Anm.
Ich benötige ja eigentlich gar keinen Event, ich will nur ein paar
Parameter aus einem µC lesen und diese visualisieren...
"Einfach warten" war gestern Abend die Idee von meiner Frau, die ist
Erzieherin :o)
Gero schrieb:> Die sendPort kann ich wohl nicht so konfigurieren dass die gesendeten> Daten nochmals im Rx-Buffer landen, oder?
Wozu sollte das gut sein, das wäre doch keine Kontrolle. Hardwaremässig
geht das auch nicht, die Einstellung "Echo on" bei einem Terminal ist
immer Softwaresache und beweist daher auch nicht, dass überhaupt was
gesendet wurde.
Gruss Reinhard
Ich habe für ähnliche Probleme bei der Kommunikation zwischen PocketPC
und GPS-Maus über BT eine einfache Lösung gefunden:
Wenn die Kommunikation in Stocken gerät, wird der Serial-Port
geschlossen und und neu geöffnet. Dann läufts reibungslos weiter, bis
der nächste Aussetzer kommt.
Hier ist das entscheidende Code-Fragment:
Bernd schrieb:> Das liest sich alles wie übelste Frickellösungen.>> Solche Konstrukte fallen doch schon beim kleinsten Windstoß zusammen.
Behauptest du.
Die Praxis zeigt, daß das seit über 500 Betriebsstunden bestens
funktioniert, im Gegensatz zu allen anderen Tricksereien, eine einmal
entgleiste COM-Verbindung zu Bluetooth wieder flott zu bekommen.
Schulwissen, keine Praxis, aber großes Maul...
naja, beim GPS-Empfänger kann man es wohl überleben, wenn mal Daten
verloren gehen ;D
Probleme liegen teilweise ja auch einfach an:
- miesen Treibern
- bei Bluetooth an Empfangsschwierigkeiten
- Fehler im Gerät zu dem verbunden wurde.
Im Fehlerfalle den Port zu schließen und einfach neu zu verbinden ist
jedenfalls besser als den Nutzer der Software mit Fehlermeldungen oder
Neustart-Prozeduren auf den Keks zu gehen.
Bernd schrieb:> Was ist wenn das Sleep(100) deutlich länger braucht als erwartet, weil> Windows mal was anderes zu tun hat?
Aber immerhin kann man sich darauf verlassen, daß es nicht früher als
100 ms nach dem Aufruf zurückkehrt - für ein
Nicht-Echtzeit-Betriebssystem reicht das aus.
Bernd schrieb:> Was ist wenn das Sleep(100) deutlich länger braucht als erwartet, weil> Windows mal was anderes zu tun hat?
Nichts!
der sleep wartet einfach bis die Antwort des µC im Empfangsbuffer ist,
wenn das jetzt meinetwegen 300ms sind, dann dauert es eben 300ms bis ich
die Daten von meinem µC in der TextBox auf dem Bildschirm habe.
C# auf Windows 7 kann niemals Echtzeit sein, es ist vielmehr eine
Visualisierung mit der ich Parameter aus einem Controller auslese und
manipuliere.
Es wäre vermutlich schlechter wenn der Sleep nur 20ms dauern würde, dann
habe ich nämlich das Problem dass mir 2 oder 3 Byte fehlen, was dann
wieder mein komplettes Protokoll verhagelt...
Ich halte es im übrigen wie Uhu es auch sagt: lieber ein schmuddeliges
Workaround das im codedesign nicht so schön ist, aber dafür dann
effektiv und zuverlässig funktioniert ohne dass ich zig Fehlermeldungen,
MessdageBoxen oder Programmabstürze bekomme.
Der verzicht auf den Event und das verwenden des Thread.sleep war die
richtige Lösung, mein Progrämmchen aberbeitet flüssig und zuverlässig
ohne einen einzigen Datengau!
...Und wenn die Software funktioniert, dann schaut da sowieso niewieder
jemand in den code hinein....