mikrocontroller.net

Forum: PC-Programmierung Visual C# Express und SerialPort


Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schönen Abend!

Nachdem ich jetzt mal mein Dev Board fertig habe und ein bisschen 
herumspiele möchte ich Daten von meinem uC empfangen und Ausgeben. z.B. 
Temperatur in Feld 1 und Luftfeuchte in Feld 2. Dazu nutze ich 
SerialPort.ReadLine() von Visual C# (Ich kenne mich nicht so aus in C#). 
Kann mir das nur jemand erklären wie das genau abläuft? Die Daten werden 
ja im Puffer abgelegt und von dort werden dann die Daten gelesen oder? 
Nur wieviel Daten liest der Befehl ein? Wie kann ich diese Auswerten? 
Wie macht man das normalerweise?

Vielleicht kann mir das jemand in einfachen Worten erklären.

BG Andreas

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ReadLine() liest so viel ein bis eine neue Zeile beginnt. Ich glaub für 
den c# Serialport ist ein Return CR-LF also Dezimal 13 - 10. Das musst 
du dann senden.

Ich würde allerdings eher das Ereignis DataReceived zum empfangen 
nehmen.
In meinem Terminalprog hab ich das so gemacht:
static void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
            if (!pause)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                if (show == false)
                    Console.Write(sp.ReadExisting());
                else
                {
                    string temp = sp.ReadExisting();
                    foreach (char c in temp)
                        Console.Write(c.ToString() +"[" +((int)c)+"]");
                }
                Console.ResetColor();
            }
}

Mit ReadExisting kannst du dann auslesen, was empfangen wurde, also im 
Puffer liegt.

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Riegebauer schrieb:
> Vielleicht kann mir das jemand in einfachen Worten erklären.

Nein!

Weil das ist nicht einfach.
Ich nehme mal an, du willst die Werte in einer WindowsForms-Anwendung in 
einer Textbox ausgeben.
Und jetzt beginnt dein Problem:

Andreas Riegebauer schrieb:
> (Ich kenne mich nicht so aus in C#).

Deine Applikation, das WindowsForms-Fenster, ist ein Thread. Und mit der 
Instanziierung der Serialport-Klasse wird ein weiterer Thread angelegt. 
Nun ist aber .Net threadsicher. D.h. man kann keine Daten direkt von 
einem in einen anderen Thread schreiben. Das lässt der Compiler zwar 
durchgehen, das Programm stürzt aber ab.

Das heisst natürlich nicht, daß man keine Daten, die mit serialport 
empfangen wurden, in eine Textbox schreiben kann.

Auch auf das Risiko hin, daß mir wieder einer vorwirft, ich mache hier 
auf dicke Hose, solltes du folgende Fragen mit ja beantworten können:

Ich weiss...
  ...was ein delegate ist
  ...wie man einen event anlegt und abfeuert
  ...was invokerequired bedeutet
  ...wie man ein callback anlegt und abfeuert

Dann können wir hier gerne weitermachen. Ansonsten wird das nichts.

mfg.

Autor: Andreas Riegebauer (blackpuma)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Hmhm... Ich weiß nicht ob ich die Sachen Verstehe aber ich habe bereits 
ein Programm das mir Daten von der Seriellen einließt und in eine 
TextBox ausgibt. Ich habe nur das Problem das mir anscheinend Daten 
verschluckt werden. Also er macht 3 mal ein Update von Feld 1, 1 mal von 
Feld 2 und 5 mal von Feld 3. Mein Programmcode kommt gleich und ein Bild 
von der Oberfläche ist auch dabei.

Vorher nur kurz zur Funktion des Puffers. Funktioniert das so wie im 
angehängten PDF?

Hier jetzt der Programcode den ich mir zusammengebastelt habe:
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace SimpleSerial_mit_EventHandler
{
    public partial class Form1 : Form
    {
        SerialPort sp = new SerialPort("com4", 9600, Parity.None, 8, StopBits.One);
        string test2;
        
        public Form1()
        {
            InitializeComponent();
        }

        /********************************************
         * 
         * Start des Empfangs
         * 
         *******************************************/
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                sp.Open();
                sp.DataReceived += new SerialDataReceivedEventHandler(sp_datareceived);
                button1.Enabled = false;
                button2.Enabled = true;
            }
            catch (Exception ex)
            { MessageBox.Show(ex.ToString()); }

        }

        /********************************************
         * 
         * Auslesen des Puffers
         * 
         *******************************************/
        private void sp_datareceived(object sender, SerialDataReceivedEventArgs args)
        {
            test2 = sp.ReadLine();
            sp.DiscardInBuffer();
            this.Invoke(new EventHandler(DisplayText));
        }


        /********************************************
         * 
         * Auswertung und Ausgabe der Messwerte
         * 
         *******************************************/
        private void DisplayText(object sender, EventArgs e)
        {
            if (test2.IndexOf("CH5") != -1)
            {
                int c = 0;
                test2 = test2.Remove(0, 3);
                try
                {
                    c = Convert.ToInt32(test2.Trim());
                    textBoxCH1.Text = String.Format("{0,7:0.00}", c / 1000.0);                    
                }
                catch (OverflowException)
                {
                    MessageBox.Show("{0} is outside the range of the Int32 type." + test2);
                }
                catch (FormatException)
                {
                    MessageBox.Show("The {0} value '{1}' is not in a recognizable format." +
                                      test2.GetType().Name + test2);
                } 
            }

            if (test2.IndexOf("CH6") != -1)
            {
                int c = 0;
                test2 = test2.Remove(0, 3);
                try
                {
                    c = Convert.ToInt32(test2.Trim());
                    textBoxCH2.Text = String.Format("{0,7:0.00}", c / 1000.0);
                }
                catch (OverflowException)
                {
                    MessageBox.Show("{0} is outside the range of the Int32 type." + test2);
                }
                catch (FormatException)
                {
                    MessageBox.Show("The {0} value '{1}' is not in a recognizable format." +
                                      test2.GetType().Name + test2);
                }
            }
            if (test2.IndexOf("CH7") != -1)
            {
                int c = 0;
                test2 = test2.Remove(0, 3);
                try
                {
                    c = Convert.ToInt32(test2.Trim());
                    textBoxCH3.Text = String.Format("{0,7:0.00}", c / 1000.0);
                }
                catch (OverflowException)
                {
                    MessageBox.Show("{0} is outside the range of the Int32 type." + test2);
                }
                catch (FormatException)
                {
                    MessageBox.Show("The {0} value '{1}' is not in a recognizable format." +
                                      test2.GetType().Name + test2);
                }
            }
        }

        /********************************************
         * 
         * Stop des Empfangs
         * 
         *******************************************/
        private void button2_Click(object sender, EventArgs e)
        {
            sp.Close();
            button1.Enabled = true;
            button2.Enabled = false;
        }
    }
}

BG
Andreas

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Riegebauer schrieb:
> private void sp_datareceived(object sender, SerialDataReceivedEventArgs args)
>
>         {
>
>             test2 = sp.ReadLine();
>
>             sp.DiscardInBuffer();
>
>             this.Invoke(new EventHandler(DisplayText));
>
>         }

Das Problem scheint mir folgendes zu sein:
Wenn Daten vorhanden sind, sagen wir mal 2 Byte, feuert der sp den 
Event.
Die Daten werden ausgelesen und angezeigt. Bevor du diese Daten 
überhaupt nur siehst, kommt aber schon der nächste Event, womit 
letztlich diese Daten überschrieben werden.

Ändere mal folgende Zeile:
textBoxCH1.Text = String.Format("{0,7:0.00}", c / 1000.0);  in
textBoxCH1.Text += String.Format("{0,7:0.00}", c / 1000.0);

zieh' die Textbox etwas länger, damit alles reinpasst.
Dann siehst ob deine Daten irgendwo sonsthin gehen oder ob ich mit 
meiner Vermutung richtig liege.

mfg.

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ich werde es zu hause versuchen nachdem ich meinen uC nicht bei der Hand 
habe. Funktioniert das mit Readline aber wie in meinem PDF skizziert?

Wie wird das normalerweise gelöst? Das was ich habe wird ja nichts 
exotisches sein. Das wird es doch öfter geben das ein Datenstrom auf der 
Seriellen daher kommt der ausgewertet werden möchte.

BG
Andreas

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch was zu dem Buffer:



Warum löscht du den Buffer?
Den würde ich gar nicht anrühren. Denn wenn du die Daten liest und dann 
den Puffer löscht, weisst du nicht, ob in der Zwischenzeit schon neue 
Daten angekommen sind.

im Eventhandler:
statt:      test2 = sp.ReadLine();
            sp.DiscardInBuffer();  unnötig. Würde ich höchstens nach dem
            Öffnen machen, um noch evtl vorhandenen Schrott rauszu- 
schmeissen.
so:
            test2 = "";
            byte[] nRB = new byte[sp.BytesToRead];
            sp.Read(nRB, 0, sp.BytesToRead);
            for (int nInd = 0; nInd < nRB.Length; nInd++)
            {
               char chData = (char)nRB[nInd];
               test2 += chData.ToString();
            }

Das ist dann völlig Datentransparent und erwartet auf der 
Schnittstelleseite keine Endebedingung.

Die Daten solltest du dann auswerten, bevor du sie anzeigst. Und solange 
zwischenspeichern, bis alles da ist.

mfg.

Autor: K.S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieso nimmst Du nicht die Komponente SerialPort aus der Toolbox ?
Da musst Du Dich um keine Threads kümmern, das macht die Komponente 
selbst.

Viele Grüße,
Klaus

Autor: Andreas Riegebauer (blackpuma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@K.S.

Das mit den Threads ist ja nicht das Problem. Das funktioniert ja 
soweit. Nur das er mir hin und wieder was verschluckt.

Ich würde halt gerne einen ganzen Datensatz lesen also bis zum NewLine 
um das auf einmal zu verarbeiten. Ich weiß aber eben nicht ob das so 
gelesen wird wie ich es skizziert habe. wenn es so ist dann sollte es 
doch funktionieren.

Das mit dem Löschen des Buffers weiß ich auch nicht wieso ich das 
drinnen habe. Muss ein Überbleibsel sein aus dem Code von dem ich das 
entnommen habe.

Wie kann ich das Abfeuern des DataReceived steuern? Also das er z.B. nur 
anspringt wenn NewLine gekommen ist?

BG
Andreas

Autor: Arc Net (arc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
K.S. schrieb:
> Wieso nimmst Du nicht die Komponente SerialPort aus der Toolbox ?
> Da musst Du Dich um keine Threads kümmern, das macht die Komponente
> selbst.

Das ist die gleiche Komponente bei der die gleiche Vorgehensweise beim 
Updaten von UI-Elementen nötig ist.

> Viele Grüße,
> Klaus

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas Eckmann schrieb:
> Deine Applikation, das WindowsForms-Fenster, ist ein Thread. Und mit der
> Instanziierung der Serialport-Klasse wird ein weiterer Thread angelegt.
> Nun ist aber .Net threadsicher. D.h. man kann keine Daten direkt von
> einem in einen anderen Thread schreiben. Das lässt der Compiler zwar
> durchgehen, das Programm stürzt aber ab.

Man kann die Threadüberorüfung abschalten und dann wedern keine 
Ausnahmen mehr ausgelöst. Ich habe fast noch nie so korrekt wie du es 
beschreibst programmiert, und trotzdem hatte ich nie Probleme. Und Daten 
von einen Thread in einen anderen gehen eben doch! Man setzt 
CheckForIllegalCrossThreadCalls auf false.

Thomas Eckmann schrieb:
> Ich weiss...
>   ...was ein delegate ist
>   ...wie man einen event anlegt und abfeuert
>   ...was invokerequired bedeutet
>   ...wie man ein callback anlegt und abfeuert

Ja delegate musst ich schon benutzen
Event auch
Invoke habe ich glaube ich nur einmal gebraucht.
Und Callback hab ich noch nie benutzt

Und hab Treadübergreifende Sachen alle ohne Events gemacht. Das 
funktioniert wuderbar.

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Riegebauer schrieb:
> Wie kann ich das Abfeuern des DataReceived steuern? Also das er z.B. nur
>
> anspringt wenn NewLine gekommen ist?

gar nicht. Der liest ja nicht mit, sondern schiebt nur durch. Die 
Auswertung muß nachher erfolgen.

mfg.

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Samuel K. schrieb:
> Man kann die Threadüberorüfung abschalten und dann wedern keine
>
> Ausnahmen mehr ausgelöst. Ich habe fast noch nie so korrekt wie du es
>
> beschreibst programmiert, und trotzdem hatte ich nie Probleme. Und Daten
>
> von einen Thread in einen anderen gehen eben doch! Man setzt
>
> CheckForIllegalCrossThreadCalls auf false.

Das kann man natürlich machen. Aber funktioniert das morgen auch noch?
Also ich meine jetzt nicht Samstag, sondern z.B. mit Visual Studio 2012 
mit Service Pack 2 von Windows 8.
Dann konvertiert man das und guckt nur noch blöd.
Damals mit Visual Studio 2003 und Framework 1 war das alles überhaupt 
kein Problem. Dann kam VS 2005 und Framework 2 und Schluss mit lustig.

mfg.

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Samuel K. schrieb:
> Ja delegate musst ich schon benutzen
>
> Event auch
>
> Invoke habe ich glaube ich nur einmal gebraucht.
>
> Und Callback hab ich noch nie benutzt

Bei der richtigen Implementierung sind wir noch gar nicht. Bislang ist 
das noch etwas halbgar.

mfg.

Autor: Sam .. (sam1994)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thomas Eckmann schrieb:
> Damals mit Visual Studio 2003 und Framework 1 war das alles überhaupt
> kein Problem. Dann kam VS 2005 und Framework 2 und Schluss mit lustig.
>
> mfg.

ICh hab das immer mit NET2.0 gemacht. Aber heißt dass man braucht wenn 
man es richtig macht immer ein event?

Autor: Thomas Eckmann (Firma: Thomas Eckmann Informationst.) (thomase)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Samuel K. schrieb:
> ICh hab das immer mit NET2.0 gemacht. Aber heißt dass man braucht wenn
>
> man es richtig macht immer ein event?

Nein braucht man nicht.
Ich pack' das Ganze nur in ein Usercontrol und zieh das dann einfach in 
die Anwendung. Dann ist das mit drei Klicks fertig. Und dafür brauch ich 
den Event.
In dem Usercontrol kann ich dann auf bestimmte Zeichen triggern und die 
Daten, erst wenn sie komplett da sind, weiterreichen. So wie Andreas das 
ja auch gerne haben möchte.

mfg.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.