Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Daten seriell von Mikrocontroller auslesen
CSharpEntwickler
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

Daten seriell von Mikrocontroller auslesen

beantworten | zitieren | melden

Hallo,

ich habe eine kleine GUI in C# erstellt. Mit dieser Gui werden/sollen Daten vom Mikrocontroller ausgelesen werden.
Es handelt sich um serielle Daten. Im Programm nutze ich die Bibliothek Syste.IO.Ports.


        private void btn_Init_Click(object sender, EventArgs e)
        {
            mySerialPort = new SerialPort("COM5");

            mySerialPort.BaudRate = 115200;
            mySerialPort.Parity = Parity.None;
            mySerialPort.StopBits = StopBits.One;
            mySerialPort.DataBits = 8;
            mySerialPort.Handshake = Handshake.None;
            mySerialPort.ReadTimeout = 100;

            //mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
            mySerialPort.Open();

            fifo_peekonly = new ConcurrentQueue<byte>();
            fifo_queue = new BlockingCollection<byte>(fifo_peekonly);

            mySerialPort.DataReceived += (sender, e) =>
            {
                byte[] buffer = new byte[mySerialPort.BytesToRead];
                if (!mySerialPort.IsOpen)
                {
                    throw new System.InvalidOperationException("Serial port is closed.");
                }
                mySerialPort.Read(buffer, 0, mySerialPort.BytesToRead);
                foreach (var b in buffer)
                    fifo_queue.Add(b);
            };

            Thread thr = new Thread(new ThreadStart(mythread));
            thr.Start();
        }

        public byte GetByteFromDevice()
        {
            byte b;
            b = fifo_queue.Take();
            return b;
        }

       public void mythread()
        {
            while(true)
            {
                if(recvByteCnt == 0)
                {
                    recvLength = GetByteFromDevice();
                    recvByte = recvLength;
                }
                else
                {
                    recvByte = GetByteFromDevice();
                }

                recvBuffer[recvByteCnt] = recvByte;

                if (recvByteCnt ≥ recvLength)
                {
                    recvFlag = 1;
                    recvByteCnt = 0;

                    Debug.Write("Complete\n");
                }
                else
                {
                    if (recvByteCnt == 0)
                    {
                        Debug.Write("Start timeout\n");
                    }
                    recvByteCnt++;
                }

                //Debug.Write(recvByte.ToString() + "\n");
            }
        }


Nun fehlt quasi noch eine TimeOut Mechanismus. Dieser soll im thread nach der if Bedingung "if (recvByteCnt == 0)" eingesetzt werden.
Wie würde man solch eine Funktionalität realisieren?
private Nachricht | Beiträge des Benutzers
CSharpEntwickler
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

beantworten | zitieren | melden

Da hätte ich noch eine weitere Frage.

Wo ist der Unterscheid zwischen ConcurrentQueue und BlockingCollection?


     fifo_peekonly = new ConcurrentQueue<byte>();
     fifo_queue = new BlockingCollection<byte>(fifo_peekonly);

Dies habe ich von folgenden Link herausgezogen für mein Projekt:
c-sharp-serial-port-sometimes-missing-data/45432817#45432817
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.928

beantworten | zitieren | melden

Zitat von CSharpEntwickler
Wo ist der Unterscheid zwischen ConcurrentQueue und BlockingCollection?
Sowas kannst Du viel schneller beantwortet bekommen, wenn Du einfach in die Docs schaust :-)

ConcurrentQueue<T> Class (System.Collections.Concurrent)
BlockingCollection<T> Class (System.Collections.Concurrent)

- ConcurrentQueue ist eine Liste mit Thread-Sicherheit
- BlockingCollection eine Liste für Blocking und Bounding, zB für den Producer Consumer Pattern relevant

Also zwei vollständig verschiedene Konzepte.

Um die Frage zu beantworten:
Zitat
Nun fehlt quasi noch eine TimeOut Mechanismus.
Wie würde man solch eine Funktionalität realisieren?
Dazu musst Du Dein Quellcode vollständig umbauen.

Threads sind ein Betriebssystem-Konzept, das Du nicht abbrechen kannst. Ein Thread kann nur abgeschossen werden und hat keinerlei Cancel-Möglichkeit (weil es eben vom Betriebssystem verwaltet wird).
Daher arbeitet man in .NET nur in sehr seltenen Fällen mit Threads, sondern man arbeitet mit Tasks.
Tasks sind eine Abstraktion von Threads; haben volle async/await-Support und können auch Cancel (zB durch ein Timeout) unterstützen.
private Nachricht | Beiträge des Benutzers
CSharpEntwickler
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

beantworten | zitieren | melden

Hallo Abt, danke für deinen Post.

Ich habe für meine Anwendung BlockingCollection benutzt. Im Thread lese ich dann die bytes mit der Methode GetByteFromDevice aus.

Also wäre in meinem Fall die andere Variante geeigneter?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von CSharpEntwickler am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.928

beantworten | zitieren | melden

4 Minuten zwischen meinem Post und Deiner Antwort. Wieso liest Dir denn die beiden Sachen nicht mal wenigstens 15 Minuten durch, um die beiden Dinge zu verstehen?

Man kann beides nutzen; kommt halt drauf an, wie man das umsetzt.
Eine BlockingCollection verwendet man - wie man in der Doku sehen kann - eigentlich mit TryAdd und GetConsumingEnumerable.
Aber um deren Anwendung zu verstehen, sollte man halt die Doku lesen, sonst wirds schwer...
private Nachricht | Beiträge des Benutzers
CSharpEntwickler
myCSharp.de - Member



Dabei seit:
Beiträge: 4

Themenstarter:

beantworten | zitieren | melden

Hallo,

ich habe nun den Empfang der Daten in einer separaten Task realisiert.
Auch das Versenden von Daten läuft in einem anderen Task.
Nun ist es so wenn ich Daten versende, dann läuft das mit dem Empfangen von Daten schief.


           bool SendFlagLedOn = false;
           bool SendFlagLedOff = false;           

           Task recvTask = new Task(new Action(OnRxFrames));
            recvTask.Start();

            Task sendTask = new Task(new Action(OnTxFrames));
            sendTask.Start();


private void OnRxFrames()
        {
            while (true)
            {
                if (recvByteCnt == 0)
                {
                    recvLength = GetByteFromDevice();
                    recvByte = recvLength;
                }
                else
                {
                    recvByte = GetByteFromDevice();
                }

                recvBuffer[recvByteCnt] = recvByte;

                if (recvByteCnt ≥ recvLength)
                {
                    recvFlag = 1;
                    recvByteCnt = 0;

                    Debug.Write("Complete\n");

                    this.Invoke(new EventHandler(DoUpDate));
                }
                else
                {
                    recvByteCnt++;
                }
            }
        }

        private void OnTxFrames()
        {
            while (true)
            {
                if(SendFlagLedOn == true)
                {
                    SendFlagLedOn = false;

                    byte[] txData = new byte[5];
                    txData[0] = 4;
                    txData[1] = 1;
                    txData[2] = 2;
                    txData[3] = 3;
                    txData[4] = 4;

                    string str = Encoding.Default.GetString(txData);
                    mySerialPort.Write(str);
                }

                if (SendFlagLedOff == true)
                {
                    SendFlagLedOff = false;

                    byte[] txData = new byte[5];
                    txData[0] = 4;
                    txData[1] = 2;
                    txData[2] = 2;
                    txData[3] = 3;
                    txData[4] = 4;

                    string str = Encoding.Default.GetString(txData);
                    mySerialPort.Write(str);
                }
            }
        }
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von CSharpEntwickler am .
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4.389

beantworten | zitieren | melden

Hallo,

was genau läuft denn schief?

Ein großer Fehler ist jetzt bei dir die erzeugten Endlosschleifen (schau mal im TaskManager auf die Prozessor-/Kernauslastung)!
Du mußt diese wartend oder blockierend machen (oder ist GetByteFromDevice() blockierend, da du ja von ConcurrentQueue und BlockingCollection geschrieben hast?). Zumindestens für die Sendeschleife sollte ein Thread.Sleep(x) hin (bei Benutzerauslösung der Flags reichen einige 100ms).

PS: Sofern du konstante Daten versendest, kann du einfach z.B. byte[] txData = { 4, 1, 2, 3, 4 }; schreiben (und sogar den string str einmalig vor der Schleife erzeugen - bzw. 2 für die beiden Fälle).
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.928

beantworten | zitieren | melden

Der eigentliche Queue Mechanismus fehlt ja nun komplett, oder übersehe ich etwas?
Weil, das war ja eigentlich schon eine gute Idee, die auch so weit verbreitet ist.

Mit der BlockingCollection, die man hier _auch_ verwenden kann, kann man das blockierende Verhalten der Tasks auch erreichen.
Flow wäre dann:

- Blocking Collection erzeugen
- Task erzeugen, der ankommende Daten verarbeitet (weitersenden, oder was auch immer), dabei GetConsumingEnumerable verwenden!
- Task erzeugen, der ankommende Daten annimmt und in die Blocking Collection schreibt (TryAdd)

Sobald keine Daten mehr kommen sollen, CompleteAdding ausführen, sodass der verarbeitende Task sich, jedoch alle Daten in der Collection noch verarbeitet werden.
Mit einem CancellationToken, der bei der Verarbeitung abgeprüft wird, kann das Canceln erreicht werden - und eben das Enforce durch CompleteAdding.
private Nachricht | Beiträge des Benutzers