C# Probleme mit dem Einlesen seriellen Ports

OP #3420076
Lesenswert?

Hallo,

ich arbeite seit einiger Zeit mit C# an einer Aufgabe zur Datenerfassung 
mehrerer serieller Schnittstellen. Das Einlesen einer einzigen seriellen 
Schnittstelle funktioniert sehr gut.

Hierzu nutze ich den DataReceveived-Handler und es werden nacheinander 
14 Bytes eingelesen, gespeichert, verarbeitet und auf einem Label 
angezeigt.

Nun zu meinem Problem:

Leider muss ich nicht nur einen seriellen Port auslesen, sondern fünf. 
Das Programm funktioniert weiterhin, allerdings brauchst das Programm 
bis zu 4 Sekunden, um das Label eines seriellen Ports zu aktualisieren. 
Das ist für meine Anwendung viel zu langsam.

Hier beispielhaft der Code für die Datenerfassung von nur zwei Ports:

Das Programm schaltet hierbei den seriellen Port 1 an und die 
Verarbeitung wird in den Unterprogrammen durchlaufen. Ist das geschehen, 
wird Port 1 geschlossen und Port 2 geöffnet. Ist die Verarbeitung dort 
abgeschlossen, wird Port 2 geschlossen und Port 1 wieder geöffnet.


// DATA RECEIVED1 
------------------------------------------------------------------------ 
---

        private void serialPort1_DataReceived(object sender, 
System.IO.Ports.SerialDataReceivedEventArgs e)
        {
                try
                {
                    if (erstesByte == 1)
                    {
                        do
                        {
                            ByteBack = serialPort1.ReadByte();
                        }
                        while (ByteBack > 32);

                        this.Invoke(new EventHandler(Fkt_CreateArray));

                        i++;

                        for (i = 1; i < 14; i++)
                        {
                            ByteBack = serialPort1.ReadByte();
                            this.Invoke(new 
EventHandler(Fkt_CreateArray));
                        }

                        this.Invoke(new EventHandler(Fkt_auswertung));

                        erstesByte = 0;

                    }

                    i = 0;

                    serialPort1.Close();
                    serialPort2.Open();

                }
                catch (System.TimeoutException)
                {
                    MessageBox.Show("Hallo?");
                }

            }

// DATA RECEIVED 2 
------------------------------------------------------------------------ 
---

        private void serialPort2_DataReceived(object sender, 
System.IO.Ports.SerialDataReceivedEventArgs e)
        {
                try
                {

                    if (erstesByte == 1)
                    {
                        do
                        {
                            ByteBack = serialPort2.ReadByte();
                        }
                        while (ByteBack > 32);

                        this.Invoke(new EventHandler(Fkt_CreateArray));

                        i++;

                        for (i = 1; i < 14; i++)
                        {
                            ByteBack = serialPort2.ReadByte();
                            this.Invoke(new 
EventHandler(Fkt_CreateArray));
                        }

                        this.Invoke(new EventHandler(Fkt_auswertung));

                        erstesByte = 0;

                    }

                    i = 0;

                    serialPort2.Close();
                    serialPort1.Open();

                }
                catch (System.TimeoutException)
                {
                    MessageBox.Show("Hallo?");
                }

        }

------------------------------------------------------------------------


Kann sich jemand vorstellen, warum das Programm so langsam ist? Ich 
komme absolut nicht weiter. Liegt es vielleicht an dem 
DataReceived-Handler? Ich wäre sehr dankbar, wenn mir jemand unter die 
Arme greifen könnte!

Gruß

steka
Gast #3420089
Lesenswert?

Steffen Kauth schrieb:
> Leider muss ich nicht nur einen seriellen Port auslesen, sondern fünf.
> Das Programm funktioniert weiterhin, allerdings brauchst das Programm
> bis zu 4 Sekunden, um das Label eines seriellen Ports zu aktualisieren.
> Das ist für meine Anwendung viel zu langsam.

ist ja klar, dein Programmstuktur ist nicht brauchbar.

In einem DataReceivedEventArgs sollte man genau so viel Byte einlesen 
wie gerade im Buffer sind, nicht mehr und nicht weniger.

Dieser code ist also dort fehl am Platz:

 for (i = 1; i < 14; i++)
                        {
                            ByteBack = serialPort2.ReadByte();



Man könnte auch für jeden Port einen Thread Starten und einfach mit Read 
einlesen.
OP #3420108
Lesenswert?

Danke für deine schnelle Antwort!

Von meiner Sendeeinheit werden kontinuierlich Daten gesendet. Muss ich 
also den Zählerstand der Buffer einlesen und ab 14 Bytes meine 
Unterprogramme aufrufen? Wie kann ich in diesem Fall auf die einzelnen 
Bytes zugreifen? Wenn ich die Bytes einlese, wird der Buffer dann wieder 
freigegeben?

Threading ist ein ganz neues Thema für mich. Was kann ich damit 
erreichen?
Gast #3420131
Lesenswert?

Steffen Kauth schrieb:
> Von meiner Sendeeinheit werden kontinuierlich Daten gesendet. Muss ich
> also den Zählerstand der Buffer einlesen und ab 14 Bytes meine
> Unterprogramme aufrufen? Wie kann ich in diesem Fall auf die einzelnen
> Bytes zugreifen? Wenn ich die Bytes einlese, wird der Buffer dann wieder
> freigegeben?

ja, genauso.

dafür kann man einen liste nehmen:

list<Byte> buffer = new list<Byte>();

im Event machst du dann

int anzahl = Port.BytesToRead();
while ( anzahl ) {
   buffer.Add( Port.ReadByte() );
   anzahl--;
}

if (buffer.length >= 14) {
   //jetzt kannst du auf die Byte mit buffer[0..13] zugreifen

   //jetzt den buffer wieder leer machen
   buffer.Clear();
}


(code hat bestimmt viele Fehler, ist nur schnell getippt)

Wenn man es mit Thread macht, braucht man diese Events nicht. Das ist 
wie als ob dein Programm dann viele dinge gleichzeitig mache kann. Aber 
dabei muss man einiges beachten.
Gast #3420358
Lesenswert?

Steffen trinkt schrieb:
> Meinst du, dass das Programm dadurch schneller wird oder liegt das
> Problem vielleicht an anderer Stelle?

das Programm ist nicht langsam, es blockiert nur. Das liegt daran das du 
erst alle Daten einsammelst und in dieser zeit kann nichts anders 
Passieren. Ja ich denke das es nach dem umbau flüssiger läuft
OP #3424011
Lesenswert?

Ich schließe die Ports, da sie alle auf die gleiche 
Verarbeitungsfunktion zugreifen (Fkt_auswertung). Damit die Funktion 
nicht gleichzeitig durchlaufen wird und es zu Fehlern kommt, möchte ich 
die Ports nacheinander "durchschalten".

Vielleicht sollte ich einfach eine seperate Verarbeitungsfunktion für 
jeden einzelnen Port anlegen. Nicht sehr elegant, aber vielleicht 
funktioniert es.
Gast #3424016
Lesenswert?

Steffen trinkt schrieb:
> Vielleicht sollte ich einfach eine seperate Verarbeitungsfunktion für
> jeden einzelnen Port anlegen. Nicht sehr elegant, aber vielleicht
> funktioniert es.

warum sollte eine Funktion nicht für viele Ports funktionieren?

Zeig uns doch mal den Quellcode, nur so können wie eventuell helfen. 
Keine kann wissen was du alles geändert hast.
OP #3424194
Lesenswert?

Hier noch einmal der Ablauf für 2 serielle Ports mit Auswertung der 
Zahlenwerte, welche von Sendeeinheit kommen:


// DATA RECEIVED1
------------------------------------------------------------------------
---

        private void serialPort1_DataReceived(object sender,
System.IO.Ports.SerialDataReceivedEventArgs e)
        {
                int anzahl = serialPort1.BytesToRead;

            while (anzahl != 0)
            {
                buffer.Add(serialPort1.ReadByte());
                anzahl--;
            }

            if (buffer.Count >= 28)
            {
                // Suche erstes Byte in Buffer --> Wert muss kleiner 32 
sein!
                do
                {
                    if (buffer[lauf] <= 32)
                    {
                        erstesByteGefunden = true;
                    }
                    else
                    {
                        lauf++;
                    }
                } while (erstesByteGefunden == false);

                for (i = 0; i < 14; i++)
                {
                    ByteBack = buffer[lauf];
                    this.Invoke(new EventHandler(Fkt_CreateArray));

                    lauf++;
                }

                this.Invoke(new EventHandler(Fkt_auswertung));

                lauf = 0;
                i = 0;
                erstesByteGefunden = false;

                buffer.Clear();

                    serialPort1.Close();
                    serialPort2.Open();

                }
            }

// DATA RECEIVED 2
------------------------------------------------------------------------
---

        private void serialPort2_DataReceived(object sender,
System.IO.Ports.SerialDataReceivedEventArgs e)
        {
                {
                int anzahl = serialPort2.BytesToRead;

            while (anzahl != 0)
            {
                buffer.Add(serialPort2.ReadByte());
                anzahl--;
            }

            if (buffer.Count >= 28)
            {
                do
                {
                    if (buffer[lauf] <= 32)
                    {
                        erstesByteGefunden = true;
                    }
                    else
                    {
                        lauf++;
                    }
                } while (erstesByteGefunden == false);

                for (i = 0; i < 14; i++)
                {
                    ByteBack = buffer[lauf];
                    this.Invoke(new EventHandler(Fkt_CreateArray));

                    lauf++;
                }

                this.Invoke(new EventHandler(Fkt_auswertung));

                lauf = 0;
                i = 0;
                erstesByteGefunden = false;

                buffer.Clear();

                    serialPort2.Close();
                    serialPort1.Open();

                }
        }

// ERZEUGUNG ARRAY - SCHREIBE BYTES IN ARRAY 
------------------------------------------------------------------------ 
---------------

        private void Fkt_CreateArray(object serialPort1_DataReceived, 
EventArgs e)
        {
            array1[i] = ByteBack;
        }

// AUSWERTUNG DER EINZELNEN ARRAYWERTE 
------------------------------------------------------------------------ 
--------------------

        private void Fkt_auswertung(object s, EventArgs e)
        {
            // AUSWERTUNG ZAHL A

            switch (((array1[1] & 0x07) * 16) + (array1[2] & 0x0f))
            {
                case 125:
                    ZahlA = 0;
                    break;
                case 5:
                    ZahlA = 1;
                    break;
                case 91:
                    ZahlA = 2;
                    break;
                case 31:
                    ZahlA = 3;
                    break;
                case 39:
                    ZahlA = 4;
                    break;
                case 62:
                    ZahlA = 5;
                    break;
                case 126:
                    ZahlA = 6;
                    break;
                case 21:
                    ZahlA = 7;
                    break;
                case 127:
                    ZahlA = 8;
                    break;
                case 63:
                    ZahlA = 9;
                    break;
                default:
                    label_Messwert_1.Text = "WAIT";
                    break;
            }

            // AUSWERTUNG ZAHL B

            switch (((array1[3] & 0x07)) * 16 + (array1[4] & 0x0F))
            {
                case 125:
                    ZahlB = 0;
                    break;
                case 5:
                    ZahlB = 1;
                    break;
                case 91:
                    ZahlB = 2;
                    break;
                case 31:
                    ZahlB = 3;
                    break;
                case 39:
                    ZahlB = 4;
                    break;
                case 62:
                    ZahlB = 5;
                    break;
                case 126:
                    ZahlB = 6;
                    break;
                case 21:
                    ZahlB = 7;
                    break;
                case 127:
                    ZahlB = 8;
                    break;
                case 63:
                    ZahlB = 9;
                    break;
                default:
                    label_Messwert_1.Text = "WAIT";
                    break;
            }


            // AUSWERTUNG ZAHL C

            switch (((array1[5] & 0x07) * 16) + (array1[6] & 0x0F))
            {
                case 125:
                    ZahlC = 0;
                    break;
                case 5:
                    ZahlC = 1;
                    break;
                case 91:
                    ZahlC = 2;
                    break;
                case 31:
                    ZahlC = 3;
                    break;
                case 39:
                    ZahlC = 4;
                    break;
                case 62:
                    ZahlC = 5;
                    break;
                case 126:
                    ZahlC = 6;
                    break;
                case 21:
                    ZahlC = 7;
                    break;
                case 127:
                    ZahlC = 8;
                    break;
                case 63:
                    ZahlC = 9;
                    break;
                default:
                    label_Messwert_1.Text = "WAIT";
                    break;
            }


            // AUSWERTUNG ZAHL D

            switch (((array1[7] & 0x07) * 16) + (array1[8] & 0x0F))
            {
                case 125:
                    ZahlD = 0;
                    break;
                case 5:
                    ZahlD = 1;
                    break;
                case 91:
                    ZahlD = 2;
                    break;
                case 31:
                    ZahlD = 3;
                    break;
                case 39:
                    ZahlD = 4;
                    break;
                case 62:
                    ZahlD = 5;
                    break;
                case 126:
                    ZahlD = 6;
                    break;
                case 21:
                    ZahlD = 7;
                    break;
                case 127:
                    ZahlD = 8;
                    break;
                case 63:
                    ZahlD = 9;
                    break;
                default:
                    label_Messwert_1.Text = "WAIT";
                    break;
            }

            Fkt_createAnzeige();
        }


*****************************************************************

Ungefährer Ablauf ist also:

1. Öffne Port1 --> Schreibe Werte in Array1
2. Auswertung Array1 --> Fkt_createAnzeige gibt nur noch Werte auf 
jeweiliges Label aus
3. Schließe Port 1 --> Öffne Port 2
4. das gleiche nochmal mit Port2

Das große Problem der Vergangenheit: Wenn Port1 und Port2 aktiv sind 
wird Array1 teilweise mit Werten von POrt1 beschrieben und teilweise mit 
Werten von Port2!

Was haltet ihr von dem Ansatz alle Ports zu öffnen, dafür allerdings 
mehrere Verarbeitungsfunktionen mit unterschiedlichen Variablen zu 
schreiben?

Z.B.: Fkt_createArray_Port1 und Fkt_auswertung_Port1, 
Fkt_createArray_Port2 und Fkt_auswertung_Port2
Gast #3424240
Lesenswert?

naja, der code ist noch recht umständlich.

1
for (i = 0; i < 14; i++)
2
                {
3
                    ByteBack = buffer[lauf];
4
                    this.Invoke(new EventHandler(Fkt_CreateArray));
5

6
                    lauf++;
7
                }

warum übergibt so jedes Byte einzeln über eine globale Variabel über 
eine Invoke Funktion?

fülle doch gleich das Array selber ab.

lauf wird auch erstmals verwendet ohne das man sieht woher es kommt. 
Muss lauf denn global sein?

der Funktion Fkt_auswertung kannst du doch einfach das Array mit den 
Daten übergeben.

Fkt_auswertung( array1 );
oder halt
Fkt_auswertung( array2 );

du hast mir zu viele Globale Variablen ( ZahlA, ZahlB ... ) du sollte 
die Variablen in einer Stukt oder Classen zusammenfassen. Dann kann man 
das Programm auf beliebig viele Ports gleichzeitig laufen lassen, ohne 
das man den code x mal schreiben muss.


DataReceived kann man auch für viele Ports gleichzeitig nutzen, dafür 
muss man dann den Sender Parameter auswerten.

Also mache eine neue Klasse wo folgenden drin ist

ComPort
BufferArray der Rowdaten
DatenArray mit den nutzdaten
ZahlA
Zahlb
...


damit kann man dann schon mal besser arbeiten und hat auch noch einen 
überblick.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren