Forum: PC-Programmierung C# SerialPort read timeout


von David1 (Gast)


Lesenswert?

Hallo Leute,

Ziel: Ich möchte Daten von einem Mikrocontroller zu meiner Software in 
C# geschrieben übertragen.

Problem:
Ich kann eine unterschiedlich lange Anzahl an Zeilen einlesen, aber dann 
ab >200(Variiert manchmal auch erst bei 800) werden keine Daten mehr 
eingelesen, obwohl noch welche gesendet werden. Kürzere Abschnitte (<150 
Zeilen) werden jedoch vollständig empfangen.

Wenn ich per HyperTerminal zugreife habe ich keine Probleme die Daten zu 
empfangen, egal mit welcher Länge.

Hintergrund
Code:
1
void OnDataReceived(object sender, SerialDataReceivedEventArgs args)
2
{
3
    if (this.IsOpen)
4
    {
5
        try
6
        {
7
            string data = this.realPort.ReadLine(); 
8
            if (this.DataReceived != null)
9
            {
10
                this.DataReceived(data);
11
            }
12
        }
13
        catch (Exception e)
14
        {}
15
    }

Hier ist die Funktion die ausgelöst wird:
1
  // Wird ausgelöst wenn Daten über den Com-Port empfangen werden
2
private void OnDataReceived(string data)
3
{
4
     queueDatensaetze.Enqueue(data);
5
}

Ich vermute dass der Fehler entweder an den Einstellung oder an dem 
Event-Konzept liegt.

Einstellungen:
1
            realPort.Parity = Parity.None;
2
            realPort.StopBits = StopBits.One;
3
            realPort.DataBits = 8;
4
            realPort.Handshake = Handshake.RequestToSend;
5
            realPort.NewLine = "\r";
6
            realPort.Encoding = Encoding.GetEncoding(28591);
7
            realPort.ReadBufferSize = 16536;
8
            realPort.WriteBufferSize = 4096;
9
            realPort.DataReceived += OnDataReceived;
10
            realPort.ReadTimeout = 6000;
11
            this.occuredTimeouts = 0;
Ich habe das ganze mit einem SerialPort Monitor beobachtet dort werden 
die Daten empfangen, OnDataReceived wird zwar aufgerufen jedoch keine 
Daten gelesen was zu einer Timeout Exception führt.

Kann jemand eine Fehlerquelle ausmachen oder hat eine vernünftige 
Quelle/Referenz für mich?

Danke im Vorraus
David

von Arc N. (arc)


Lesenswert?

Dürfte daran liegen, dass im DataReceived-Event mit ReadLine auf die 
nächste vollständige Zeile gewartet wird. ReadLine blockiert entweder 
bis die Zeile vollständig gelesen ist oder, falls so eingestellt, bis 
zum Timeout. Was passiert jetzt wenn während ReadLine wartet, neue Daten 
eintreffen...
Etwas aufwändiger wäre eine Lösung, die im DataReceived-Event mit 
ReadExisting erstmal einen Buffer füllt und diesen Buffer in einem 
separaten Thread auseinanderzunehmen.

von Daniel G. (daniel83)


Lesenswert?

Die Klasse SerialPort ist ein bischen labil. Meiner Erfahrungnach sollte 
man soviel wie möglich selbst machen und die Funktione dieser Klasse 
soweit wie möglich bei Seite legen. Das Verhalten ist sehr merkwürdig.
OnDataReceived kann wärendeiner Kommunikation, die von dir als eine 
betrachtet werden durchaus mehrfach ausgelöst werden. Dann hast du 
mehrere Threads, die Paralell auf das Zeilenende warten.

Du hast 2 mal OnDataReceived geschrieben, das ist jedoch bestimmt nur 
ein Fehler beim Kopieren gewesen.

Als referenz hönnte ich dir das hier 
http://www.mycsharp.de/wbb2/thread.php?threadid=43748 anbieten. Das 
Template hat mir sehr geholfen und zeigt wie man ordentlich mit der 
Klasse arbeiten kann.

SerialPort hat mir in einigen Anwendungen den letzten Nerv geraubt

von David1 (Gast)


Lesenswert?

Die Readexisting Methode wäre natürlich eine Alternative, das würde ja 
dann aber mehr Aufwand bedeuten da ich die Daten zusammensetzen und 
wieder splitten muss.

Kann ich nicht einfach in einer while-Schleife die Readline-Methode 
benutzen und von den Event gesteuerten Empfang der Daten abweichen?

@Daniel:
das 2.OnDataRecieved ist ein weiteres Event was von dem ersten 
OnDataRecieved ausglöst, etwas verwirren die Notation, werde ich ändern.

Den Ansatz im Beispiel werde ich mal ausprobieren.

Ich hatte die ganze Zeit eher nach einem Speicherproblem gesucht, weil 
ja geringe Zeilen sauber übertragen werden.

von Daniel G. (daniel83)


Lesenswert?

Das mit den kurzen Übertragungen würde ich als Zufall beschreiben. 
OnDataReceived ist wie gesagt eher unzuverlässig. Weist du vorher 
wieviele Daten (Zeilen) kommen? Dann könntest du im OnDataReceived 
entsprecehnd lange warten und dir den Timeout selbst bauen.
1
// Warte auf Antwort
2
            do
3
            {
4
                Thread.Sleep(10);
5
                aktuelleZeit = DateTime.Now;
6
            } while (timeoutZeit + timeout > aktuelleZeit && Port.BytesToRead < 9);

Ich mache das gerne in etwa so. Ich weis allerdings auch wann ich auf 
daten warten muss.
Eine Variante wäre, dass du wenn zu begin der Übertragung der erste 
OnDataReceived ausgelöst wird ein Flag z.B. im TAG des SerialPort 
Objekts setzt und weitere OnDataReceived damit ausschließt, weil du hier 
darauf Prüfst.

Das geht jedoch nur wenn du aus deinen Daten am anfang herausbekommst 
wieviele du erwartest oder dies bereits zur Entwicklungszeit klar ist.

von David 1 (Gast)


Lesenswert?

Also die Anzahl der Zeilen variert stark(zwischen 4 und 1340).

Ich hatte mir das so vorgestellt:

Pseudocode
1
comPort.Open()
2
comPort.SendeBefehl(Start)
3
do
4
{
5
   queueDatensaetze.Enqueue(comPort.ReadLine()); 
6
7
8
}while(EndindikatorVorhanden(data);
9
10
comPort.Close();
11
DoSomethingWith(queueDatensaetze);

Ich werde mal anhand der Beipiele und Überlegungen einige der Sachen 
austesten.

von Daniel G. (daniel83)


Lesenswert?

Was passiert, wenn gerade nichts zu lesen da ist? Exception? du wirst 
vermutlich eine Sehr hohe CPU auslastung bekommen, deshalb ist bei mir 
das thread.Sleep(10) drin. in der Zeit bin ich eigentlich schon 5mal 
fertig.

von David 1 (Gast)


Lesenswert?

In meiner Anwendung sende ich den Befehl zur Datenübertragung und ab da 
an werden nur noch Daten geschickt.
Wenn keine Datenübersendet werden kann nur ein Fehler dafür 
verantwortlich sein, deswegen ist eine Exception in dem Fall auch 
richtig.

Ein Problem mit der CPU-Last konnte ich noch nicht erkennen, in meinem 
Tests war die Auslastung des Prozesses maximal bei 10% aber meist 
zwischen 3-6%.

Ich warte jetzt noch bis sich ein paar mehr Daten angesammelt haben um 
das ausgiebig zu testen.

In meiner Implementierung verarbeite ich die Daten auch gleich, also 
hänge sie nicht in einem Fifo.

Danke schon mal für die vielen nützlichen Hinweise.

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.