Hallo zusammen,
ich möchte für eine µC Anwendung in MS Visual Studio 2008 C++ ein
kleines Fenster programmieren. Der µC kommunziert über die serielle
Schnittstelle.
Das Senden habe ich schon hinbekommen:
Damit kann ich beliebig lange Byte-Arrays durch Eintragen in den FIFO
(Enqueue) versenden.
Soweit sogut.
Nur der Empfang will mir nicht gelingen.
Die Antwort des µC kann unterschiedliche Länge aufweisen (zwischen 6 und
250 Bytes). Nur leider will mir das nicht gelingen, den Port geeignet
anzusprechen bzw. zu konfigurieren.
Kann mir jemand einen Tip geben, was ich zutun habe, damit ich (also
meine Anwendung) ein komplettes Byte-Array bekomme, wenn die Übertragung
beendet ist?
Das Ende einer Übertragung soll definiert sein als Pause länger als zwei
Bytes zwischen zwei Übertragungen.
Versuche mit der Methode RS232->Read, bzw. den Read-EventHandler
brachten nur Teile der empfangenen Nachricht ins Array. Der Rest stand
dann im Array beim nächsten Aufruf.
Aber ein manuelles Zusammenbauen ist nicht möglich, da es kein Zeichen
gibt, welches das Ende darstellt.
Kann mir jemand helfen?
Matthias Lipinsky schrieb:> Aber ein manuelles Zusammenbauen ist nicht möglich, da es kein Zeichen> gibt, welches das Ende darstellt.
Und woher weiß deine Anwendung dann, dass die Übertragung zu Ende ist?
Ist eine größere Pause drin, könnte man es über ein Timeout realisieren.
Einfach die empfangenen Daten byteweise abholen und wenn z.B. 1s keine
neuen Daten kommen, ist die Übertragung zu Ende und es geht beim
nächsten Zeichen von vorn los. Ist allerdings nicht optimal. Wenn ich
Daten über die serielle Schnittstelle einlese, verwende ich meist CR+LF
als Endmarkierung. Das hat den Vorteil, ich kann den String mit
Readline() einlesen. Das geht allerdings nur bei Ascii-Daten. Vorher
habe ich noch ein Event definiert, der Bescheid sagt, wenn etwas zu
empfangen ist.
Google ist in dem Fall dein Freund, es gibt bei MSDN und Co. haufenweise
Infos dazu. Vielleicht auch mal in Richtung VB schauen, die .Net- und
API-Funktionen sind unabhängig von der Sprache so ziemlich gleich...
>Und woher weiß deine Anwendung dann, dass die Übertragung zu Ende ist?>Ist eine größere Pause drin, könnte man es über ein Timeout realisieren.
RIchtig. Zwischen den Nachrichten ist eine Pause von mindestens zwei
Bytelängen/zeiten. Das ist im µC so programmiert.
>CR+LF als Endmarkierung.>Das geht allerdings nur bei Ascii-Daten.
Aber es sind eben keine ASCII-Daten. Reine hex Daten.
>es gibt bei MSDN und Co. haufenweise Infos dazu
Hab ich schon. Da gibt es in der Schnittstelle Angaben für zB Timeout.
Ich hab damit auch schon viel probiert, aber bisher ohne den gewünschten
Erfolg.
Irgendjemand muss doch dasselbe PRoblem mal gehabt haben. Oder
verschicken alle anderen nur ASCII Daten? ;-(
Matthias Lipinsky schrieb:> eine Pause von mindestens zwei Bytelängen/zeiten.
Das bekommst du m.M.n. mit Windows nicht sauber detektiert. Die
Zeitspanne ist zu kurz. Windows ist kein Echtzeitbetriebssystem und kann
demzufolge mal etwas länger in einem Tread festhängen. Je nach
Übertragungsrate sind zwei Bytelängen höchstens 2 ms, eher weniger.
Jens schrieb:> Je nach> Übertragungsrate sind zwei Bytelängen höchstens 2 ms, eher weniger.
Und die Timeslots bei Windows Threads sind, meiner Erfahrung nach, immer
so gut 10ms lang...
Vergiss das am besten direkt und überleg dir was, womit du das Ende der
Übertragung sicher detektieren kannst. Eventuell kannst du ja die
Steuerleitungen der seriellen Schnittstelle dafür verwenden ;-)
Die Pause zu verlängern wäre ja nur eine Fingerübung.
Trotzdem muss das ja klappen. Wenn ich auf nem zweiten Rechner mit nem
Terminalprogramm eine Reihe von Bytes versende, dass diese komplett am
Stück ankommen. Und nicht zB der RxEvent Handler irgendwo innerhalb
aufgerufen wird...
EDIT:
>so gut 10ms lang...
Eine Pause von mind 10ms wäre ja seitens des µC machbar.
>womit du das Ende der Übertragung sicher detektieren kannst.
Da es Hex-Daten sind, ist das nicht möglich. ALle Bytes sind
gleichberechtigt und können mitten im Strom als Datum vorkommen.
Matthias Lipinsky schrieb:> Trotzdem muss das ja klappen. Wenn ich auf nem zweiten Rechner mit nem> Terminalprogramm eine Reihe von Bytes versende, dass diese komplett am> Stück ankommen. Und nicht zB der RxEvent Handler irgendwo innerhalb> aufgerufen wird...
Der EventHandler wird mehr oder weniger an zufälliger Stelle während des
Empfangs aufgerufen. (nicht 100% richtig, man kann eine Byteanzahl
definieren, nach der er aufgerufen wird, aber das hilft bei unbekannter
Länge nicht.)
Normalerweise schreibe ich die empfangenen Daten im EventHandler
OnReceive() in eine "globale" Liste (z.B. List<byte> in C#) und prüfe
dann zyklisch, ob die Bedingung, die das Ende der Übertragung anzeigt,
aufgetreten ist. Wenn das z.B. die Steuerleitung ist, könntest du im
Event für das Ändern des Status einer dieser Leitungen die Liste wo
anders abspeichern, leeren und dann die Daten verarbeiten...
Matthias Lipinsky schrieb:>>womit du das Ende der Übertragung sicher detektieren kannst.> Da es Hex-Daten sind, ist das nicht möglich. ALle Bytes sind> gleichberechtigt und können mitten im Strom als Datum vorkommen.
Steuerleitungen sind keine Option? Die sind, glaub ich, mal für den
Zweck erdacht worden.
Ist die Länge des jeweiligen Streams vor dem ersten Byte bekannt? Wenn
ja, könnte man ein kleines Protokoll definieren, wo als erstes Byte
immer die Länge der Übertragung gesendet wird.
Jens schrieb:> Ist die Länge des jeweiligen Streams vor dem ersten Byte bekannt? Wenn> ja, könnte man ein kleines Protokoll definieren, wo als erstes Byte> immer die Länge der Übertragung gesendet wird.
Wobei sich dabei das Problem stellt, dass, sollte ein Übertragungsfehler
auftreten, das Programm völlig aus dem Tritt gerät.
Matthias Lipinsky schrieb:>>Und woher weiß deine Anwendung dann, dass die Übertragung zu Ende ist?>>Ist eine größere Pause drin, könnte man es über ein Timeout realisieren.>> RIchtig. Zwischen den Nachrichten ist eine Pause von mindestens zwei> Bytelängen/zeiten. Das ist im µC so programmiert.>>>CR+LF als Endmarkierung.>>Das geht allerdings nur bei Ascii-Daten.>> Aber es sind eben keine ASCII-Daten. Reine hex Daten.
Ist der Inhalt der vom Controller empfangenen Daten wirklich nur anhand
der Anzahl der Bytes zu erkennen und nicht aus den Daten selbst?
Zum anderen
> Die Antwort des µC kann unterschiedliche Länge aufweisen (zwischen 6 und> 250 Bytes). Nur leider will mir das nicht gelingen, den Port geeignet> anzusprechen bzw. zu konfigurieren.
Falls das heißt, dass der Controller nur dann sendet, wenn er gefragt
wurde, könnte beim Senden gespeichert werden, wie viele Bytes im
Received-Event eingelesen werden sollen (Problem: Übertragungsfehler,
Lösung: z.B. Timer mitlaufen lassen)
>Falls das heißt, dass der Controller nur dann sendet, wenn er gefragt>wurde,
Das ist definitiv so.
>könnte beim Senden gespeichert werden, wie viele Bytes im Received-Event >eingelesen werden sollen
Das weiß ich ja eben nicht. Die Antwort kann ja unterschiedlich lang
sein.
>Timer mitlaufen lassen
Ich hab das jetzt mal mit der Hand programmiert:
Der DataRecv-Event trägt die Daten in ein Hilfsarray ein. Mit jedem
empfangenem Datum wird ein Zeitstempel genommen. Werden länger als 100ms
keine Daten empfangen (kein DataRecv Event), so nehme ich das als
komplett an.
Das scheint zu klappen, aber
1) ist das die Lösung?
2) WIeso empfange ich Bitfehler in jeder Nachricht?
Bsp:
Ich sende per Tastendruck im Terminal 15Bytes: "abcdefgh12345$0D$0A"
Was ankommt, siehe Anhang. Ich arbeite zZ mit 38k4, aber auch bei 4800
passiert dasslebe....