Forum: PC-Programmierung VS2008 Problem mit SerailPort EMpfang


von Matthias L. (Gast)


Lesenswert?

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:
1
  RS232  = gcnew System::IO::Ports::SerialPort;
2
  TxFifo = gcnew System::Collections::Generic::Queue<array<unsigned char>^>;
3
4
  //-- Senden:
5
  if ( TxFifo->Count == 0 )  return;
6
  array<unsigned char> ^arData;
7
  arData = TxFifo->Dequeue();
8
  RS232->Write( arData, 0, arData->Length );

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?

von Jens (Gast)


Lesenswert?

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...

von Matthias L. (Gast)


Lesenswert?

>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? ;-(

von Jens (Gast)


Lesenswert?

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.

von Sven H. (dsb_sven)


Lesenswert?

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 ;-)

von Matthias L. (Gast)


Lesenswert?

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.

von Sven H. (dsb_sven)


Lesenswert?

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...

von Sven H. (dsb_sven)


Lesenswert?

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.

von Jens (Gast)


Lesenswert?

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.

von Sven H. (dsb_sven)


Lesenswert?

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.

von Arc N. (arc)


Lesenswert?

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)

von Matthias L. (Gast)


Angehängte Dateien:

Lesenswert?

>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....

von Sven H. (dsb_sven)


Lesenswert?

Vielleicht stimmt irgendwas mit der Baudrate noch nicht zu 100%?

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.