Forum: PC-Programmierung .NET SerialPort mit FT232R Handshake


von Alexander H. (ill_son)


Lesenswert?

Hallo,

ich bin dabei, mit C# eine Anwendung zu schreiben, die via Serial Port 
(FT232R) mit einem externen Gerät kommuniziert. Interessant ist nur die 
Richtung Gerät -> PC, weil da ordentlich Daten übertragen werden. Zur 
Zeit benutze ich die .NET SerialPort Klasse mit den Einstellungen 256000 
Baud, 8N1 und arbeite mit DataReceived_Event wie folgt:
1
public void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
2
{
3
    SerialPort port = sender as SerialPort;
4
5
    byte[] bytes;
6
7
    if (port != null)
8
    {
9
        if (port.IsOpen)
10
        {
11
            int b2r = port.BytesToRead;
12
            if (b2r > 0)
13
            {
14
                bytes = new byte[b2r];
15
                port.Read(bytes, 0, b2r);
16
            }
17
        }
18
        stream.WriteLine(b2r.ToString()); //Pufferfüllstand loggen
19
    }
20
}

Folgende Probleme haben sich ergeben, bei denen ich nicht weiterkomme:

Ich habe festgestellt, dass das Event während der Kommunikation immer 
wieder auch dann gefeuert wird, wenn gar keine Daten im Puffer sind 
(Bytes2Read = 0), so etwa jedes 2-3 Mal ist das der Fall. Kann das mit 
dem FTDI chip zutun haben? Das größere Problem habe ich aber mit dem 
Handshake.

Ich habe Handshake mit
1
sp.Handshake = Handshake.RequestToSend;
eingestellt.

Aber selbst wenn ich einen Pufferüberlauf erzwinge (Event abmelden)

wird RTS nicht gesetzt. Manuell kann ich sie mit
1
sp.EnableRTS = wert;

setzten. Woran liegt das?

Müsste ich hier die FTDI D2XX.dll benutzen?


Grüße, Alex

: Bearbeitet durch User
von bluppdidupp (Gast)


Lesenswert?

Vermutlich ist e.EventType == SerialData.Eof ;D

von Alexander H. (ill_son)


Lesenswert?

Das kann ich ja mal testen. Allerdings sagt die MSDN dazu:

Eof - Das Dateiendezeichen wurde empfangen und im Eingabepuffer 
platziert.

BytesToRead ist aber 0.

Damit kann ich aber eigentlich auch leben. Mein eigentliches Problem ist 
das oben beschriebene Handshake. Vielleicht hat ja dazu noch jemand eine 
Idee.

Grüße, Alex

von Peter II (Gast)


Lesenswert?

kann es ein das du das Event 2 registriert hast? Dann würde beim 2.Event 
keine Daten mehr vorhanden sein.

Ich habe auch schon einiges mit FT232R und C# gemacht, mir ist das noch 
nie aufgefallen das nach einen Event keine Daten gekommen sein.

Mittlerweile nehme ich kaum noch den Event, ich verwende einen eigenen 
Thread und mache ein normales Read, da hat man das Timeout gleich unter 
Kontrolle.

von Alexander H. (ill_son)


Lesenswert?

Hallo Peter,

danke für die Antwort. Das Event ist definitiv nur einmal registriert. 
Ich hab ein klieines Testprogramm geschrieben, das nur ein paar Zeilen 
Code enthält.
Fällt dir zu der Handskake-Problematik noch was ein? Bin auch kurz 
davor, den Port mit einem Timer zu pollen. Wie realisierst du das mit 
dem Extra-Thread, auch als Timer?

Grüße, Alex

von Peter II (Gast)


Lesenswert?

Alexander H. schrieb:
> Fällt dir zu der Handskake-Problematik noch was ein?
nein, habe ich noch nie verwendet.

> Bin auch kurz
> davor, den Port mit einem Timer zu pollen.
für was willst du den pollen?

> Wie realisierst du das mit
> dem Extra-Thread, auch als Timer?
nein, read blockiert ja bis Daten da sind, oder ein Timeout auftritt.

von Alexander H. (ill_son)


Lesenswert?

Na z.B. einen Timer mit Intervall von 200ms - 500ms (je nach 
Puffergröße) verwenden und im Tick_Event den Port auslesen.

von bluppdidupp (Gast)


Lesenswert?

Alexander H. schrieb:
> Eof - Das Dateiendezeichen wurde empfangen und im Eingabepuffer
> platziert.
>
> BytesToRead ist aber 0.

Das ist das normale Verhalten. Das EOF-DataReceived wird einfach 
unmittelbar nach einem Chars-DataReceived Event ausgelöst, womit man das 
EOF-Char dann schon weggelesen hat. Das EOF-DataReceived ist quasi nur 
eine Art "Marker" und kann völlig ignoriert werden.


>Aber selbst wenn ich einen Pufferüberlauf erzwinge (Event abmelden)
>wird RTS nicht gesetzt. Manuell kann ich sie mit
Wie lange testest du das denn? Beachtet werden muss noch dass auch der 
Treiber ggf. noch ordentlich Daten puffern kann und "schick mir erstmal 
nichts mehr" dadurch ggf. erst sehr spät kommen kann.
Oder gehen schon Daten verloren?

von Alexander H. (ill_son)


Lesenswert?

Guten Morgen,

ich sende kilobyteweise Daten. Im Moment arbeite ich nur mit einem 
kleinen Testprogramm, um den Problemen mit dem SerialPort auf die Spur 
zu kommen und das Handshake auf die Reihe zu bekommen. Da gehen keine 
Daten verloren. In der eingentlichen Anwendung gehen dann Daten 
verloren, wenn sie auf einem alten Rechner (Single-Core, XP) läuft. Auf 
einem etwas schnelleren Rechner passiert nichts.

Zum Handshake habe ich folgendes probiert: Handshake für den Port auf 
RTS gesetzt, kein Event aboniert und den Port mit Daten geflutet. Da 
hätte, wenn es denn geht, irgendwann die RTS-Leitung mal den Pegel 
ändern müssen.

Ich habe mal noch etwas recherchiert, Eof scheint beim Serial Port 
obsolet zu sein, ist ein Relikt aus älteren Zeiten.

Grüße, Alex

von Peter II (Gast)


Lesenswert?

bluppdidupp schrieb:
> Das ist das normale Verhalten. Das EOF-DataReceived wird einfach
> unmittelbar nach einem Chars-DataReceived Event ausgelöst,

blöde frage, woher soll denn bei Seriell ein EOF kommen, wenn man Daten 
im Binary Modus überträgt?

von Alexander H. (ill_son)


Lesenswert?

Ich hab das jetzt mal ausprobiert. Wenn der Puffer leer ist beim Event, 
ist der EventType tatsächlich Eof. Aber das hieße ja, dass Bytes, die 
Eof entsprächen, einfach verschluckt würden, was ja auch nicht sein 
darf. Ich vermute aber eher, das nach einem Datenblock, der Eof 
enthielt, nochmal ein Event kommt, das dann das Eof signalisiert. Alles 
andere wäre ja Unsinn.
Aber wie schon gesagt, das ist für mich eher nebensächlich. Mein Problem 
ist das Handshake.

Grüße, Alex

: Bearbeitet durch User
von bluppdidupp (Gast)


Lesenswert?

Peter II schrieb:
> blöde frage, woher soll denn bei Seriell ein EOF kommen, wenn man Daten
> im Binary Modus überträgt?

Das liegt wohl daran, das bei MS da wohl jemand zu tief ins Glas 
geschaut hat ;D
Es wird gesetzt:
this.dcb.EofChar = 26; // ohne Relevanz ;D
this.dcb.EvtChar = 26; // wird unnötigerweise mit WaitForCommEvent 
"abgefragt" und wird an folgender Stelle dann als Eof ausgelöst:
1
// System.IO.Ports.SerialStream.EventLoopRunner
2
private void CallReceiveEvents(object state)
3
{
4
  // [...]
5
  if (serialStream.DataReceived != null)
6
  {
7
    if ((num & 1) != 0)
8
    {
9
      serialStream.DataReceived(serialStream, new SerialDataReceivedEventArgs(SerialData.Chars));
10
    }
11
    if ((num & 2) != 0)
12
    {
13
      serialStream.DataReceived(serialStream, new SerialDataReceivedEventArgs(SerialData.Eof));
14
    }
15
  }
16
}

...sofern der jeweilige Treiber das nicht einfach ignoriert, wird also 
immer wenn 0x1A (dezimal 26) in den eingehenden Daten vorkommt ein EOF 
ausgelöst ;D
siehe auch hier: 
http://stackoverflow.com/questions/12483711/serialdata-eof-circumstances/13438355#13438355

von bluppdidupp (Gast)


Lesenswert?

Alexander H. schrieb:
> ch vermute aber eher, das nach einem Datenblock, der Eof
> enthielt, nochmal ein Event kommt, das dann das Eof signalisiert. Alles
> andere wäre ja Unsinn.

Nein, beim vorangegangenen DataReceived-Event war das EOF (0x1A) schon 
mit dabei - Geht also nicht verloren.

Zum Handshake-Problem kann ich sonst leider auch nichts weiter 
beitragen, damit habe ich bislang nichts gemacht. Ein Board mit dem 
ft232r hätte ich zwar rumliegen, da könnte ich aber frühestens am 
Wochenende mal mit rumprobieren.

von Alexander H. (ill_son)


Lesenswert?

Wenn Du das mal machen könntest, wäre das natürlich toll. Wie gesagt, 
ich sehe noch eine Chance in der Verwendung des D2XX treibers von FTDI.

Grüße, Alex

von Peter II (Gast)


Lesenswert?

Was erhoffst du dir denn von dem Handshake?

Scheinbar verwende es ja kaum jemand, ich wüsste auch nicht wozu man es 
in der Richtung µC -> PC brauchen sollte. Der PC ist schnell genug um 
die Paar Bytes zu verarbeiten.

von Alexander H. (ill_son)


Lesenswert?

Naja, offensichtlich ja nicht. Die alte Mühle, die ich hier zu 
Testzwecken rumstehen habe, packt es nicht. Andere Rechner schaffen es, 
deshalb würde ich den FTDI als Flaschenhals mal ausschließen.

von Peter II (Gast)


Lesenswert?

Alexander H. schrieb:
> Naja, offensichtlich ja nicht. Die alte Mühle, die ich hier zu
> Testzwecken rumstehen habe, packt es nicht. Andere Rechner schaffen es,
> deshalb würde ich den FTDI als Flaschenhals mal ausschließen.

oder Programmierfehler. Man kann ich C# auch viele Fehler machen, damit 
schafft es dann ein aktuell PC nicht mehr.

z.b. das ständig hinzufügen der Daten an ein Array. Oder das byteweise 
verarbeiten, wenn es auch blockweise geht.

Auch das arbeiten mit dem Event bedeutet einen gewissen Overhead.

Kannst du etwas mehr von dem Programm zeigen?

von Alexander H. (ill_son)


Lesenswert?

Hallo Peter,
1
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
2
{
3
    SerialPort port = sender as SerialPort;
4
    int bytes2Read = 0;
5
    try
6
    {
7
         if (port != null)
8
         {
9
             if (port.IsOpen)
10
             {
11
                 bytes2Read = port.BytesToRead;
12
                 byte[] bytes = new byte[bytes2Read];
13
                 this.portResult.ReadBytes = port.Read(bytes, 0, bytes2Read);
14
                 this.portResult.FrameBuffer.Enqueue(bytes);
15
             }
16
         }
17
    }
18
19
    catch (Exception exc) { /*throw new Exception(exc.Message, exc);*/ }
20
    this.portResult.GetFrameFromBufferAsynch();
21
}

GetFrameFromBufferAsynch läuft dann in einem eigenen Thread, FrameBuffer 
ist eine ConcurrenQueue. Ich weiß nicht, wo ich das noch straffen soll.

Ich verweise mal noch auf Thread www.mikrocontroller.net/topic/338068

So hat alles begonnen.

Grüße, Alex

von Peter II (Gast)


Lesenswert?

Alexander H. schrieb:
> GetFrameFromBufferAsynch läuft dann in einem eigenen Thread, FrameBuffer
> ist eine ConcurrenQueue. Ich weiß nicht, wo ich das noch straffen soll.

dann finde ich das ganze über den Event schon sehr umständlich. Warum 
erst alles über ein Event einlesen, dann in eine neue Liste stecken die 
dann wieder über eine Thread verarbeitet wird.

mach doch gleich alles in dem Thread, oder ist selber so langsam das er 
die Daten nicht schnell genug verarbeiten kann?

von Alexander H. (ill_son)


Lesenswert?

Verwende das Kiss-Protokoll. Und das Auseinanderdröseln der Daten mache 
ich im Extrathread. Da muss ich ja jedes Byte anfassen.

von bluppdidupp (Gast)


Lesenswert?

bluppdidupp schrieb:
> Ein Board mit dem
> ft232r hätte ich zwar rumliegen, da könnte ich aber frühestens am
> Wochenende mal mit rumprobieren.

Da muss ich wohl noch ein Wochenende schieben ;D

von Alexander H. (ill_son)


Lesenswert?

Ich denke, solange kann ich noch warten ;)

Grüße, Alex

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.