Laden...

Chart mit Messdaten füllen

Erstellt von AceTecNic vor 2 Jahren Letzter Beitrag vor 2 Jahren 896 Views
A
AceTecNic Themenstarter:in
51 Beiträge seit 2018
vor 2 Jahren
Chart mit Messdaten füllen

Guten morgen,

ich möchte mir mithilfe eines Microcontroller ein Messwerkzeug bauen, damit ich Druck und Temperatur auslesen und aufzeichnen kann.
Die Messung selber soll später auf eine Minute begrenzt werden. So viel mal vorab.

Die Seite mit dem Microcontroller funktioniert soweit und ich kann über den USB-Port die Daten einlesen. Aktuell scheitere ich aber beim Versuch, die Messwerte in die Chart zu übergeben.
Könnt ihr mir einen Tipp geben, wie ich die Messwerte in mein Chart bekommen kann? Wenn ich feste Werte nehme, bekomme ich das hin aber halt auch nur dieses Balkenchart und kein Linienchart 😁

Ich möchte keine fertigen Codes haben, nur eine kurze Hilfestellung mit welcher Funktion ich das hinbekommen könnte 🙂

Vorab schonmal DANKE fürs Gedanken machen!

Mein bisheriger Code:
(Konnte man den nicht mal in [Spoiler] setzen?)


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.IO.Ports;
using System.Timers;

namespace HDR_Testprogramm
{
    public partial class Form1 : Form

    {
        public Form1()
        {
            InitializeComponent();

            //Sucht nach verfügbaren Ports und listet diese auf
            string[] ports = SerialPort.GetPortNames();
            foreach(string port in ports)
            {
                ToolStripMenuItem item = new ToolStripMenuItem(port);
                item.Click += cOMPortToolStripMenuItem_Click;
                cOMPortToolStripMenuItem.DropDownItems.Add(item);
            }
            //_________________________________________________________________________
        }


        private void cOMPortToolStripMenuItem_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            serialPort1.PortName = sender.ToString();
            serialPort1.Open();
        }

        private void btn_messungstarten_Click(object sender, EventArgs e)
        {
            int ibar = 0;
            try
            {
                string bar = serialPort1.ReadExisting();
                richTextBox1.AppendText(bar);
                chart_druck.Series.Clear();
                ibar = Convert.ToInt16(bar);
                chart_druck.Series.Add("druck").Points.Add(ibar);
            }
            catch
            {
                MessageBox.Show("Zuerst Port auswählen!");
            }
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //string bar = serialPort1.ReadExisting();
            //label1.Text = bar;
        }

        private void chart_druck_Click(object sender, EventArgs e)
        {
            chart_druck.Series.Clear();
        }

        private void btn_messungstop_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
        }

        private void richtextbox_leeren_Click(object sender, EventArgs e)
        {
            richTextBox1.Clear();
        }
    }
}

4.938 Beiträge seit 2008
vor 2 Jahren

Für ein Liniendiagramm mußt du den ChartType der Serie(n) auf SeriesChartType.Line ändern.
Hier zwei Beispiele:
Create Line Chart (Graph) in Windows Forms Application using C# and VB.Net
Windows Forms: How to create line chart in C#

Ob nun feste oder variable Werte, du mußt diese dann der Points-Eigenschaft übergeben.
Mit chart_druck.Series.Add("druck").Points.Add(ibar) fügst du jedesmal eine weitere Serie mit einem Wert hinzu.
Erzeuge einmal die Serie und füge dann dazu die Werte jedesmal hinzu.

A
AceTecNic Themenstarter:in
51 Beiträge seit 2018
vor 2 Jahren

Danke für deine Info!

Mit dem ersten Link komme ich nocht nicht klar - schau ich mir heute Abend in Ruhe an.
Bei dem zweiten kam ich dafür zur besseren Erkenntnis 😁

Aktuell sieht mein Codeschnipsel so aus:


        private void btn_messungstarten_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 3; i++)
            {
                
                string bar = serialPort1.ReadExisting();
                int ibar = Convert.ToInt32(bar);
                chart_druck.Series.Clear();
                chart_druck.Series.Add("Druck");
                chart_druck.Series[0].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line;
                chart_druck.Series[0].Points.AddXY(i,ibar);
            }
            serialPort1.Close();
        }

Allerdings werden mir die Punkte noch nicht angezeigt wie gewollt 😁

Ich versuche mich heute Abend nochmal daran.

A
AceTecNic Themenstarter:in
51 Beiträge seit 2018
vor 2 Jahren

Mein chart zeigt nun endlich was an 😁
Noch nicht wirklich schön, aber froh bin ich trotzdem darüber.

Wie läuft das denn ab mit der USB Schnittstelle. Wenn ich länger warte, bis ich den serialPort1 abfrage, habe ich deutlich mehr im chart. Wenn ich das ganze schneller wiederhole, weniger.
Sammeln sich die Daten und warten bis sie jemand abholt oder wie kann man sich das vorstellen? 😁

Ich hänge mal den Code von meinem Arduino noch mit ran.



        private void btn_messungstarten_Click(object sender, EventArgs e)
        {
            chart_druck.Series.Clear();
            chart_druck.Series.Add("Druck");
            chart_druck.Series[0].ChartType = SeriesChartType.Line;
            string readbar = serialPort1.ReadExisting();
            foreach (int bar in readbar) 
            {
                /*
                for (int i = 0; i < 1; i++)
                {
                    chart_druck.Series[0].Points.Add(bar);
                }
                */
                chart_druck.Series[0].Points.Add(bar);
            }
            //serialPort1.Close();
        }


ArduinoCode:


void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println(2);
  delay(333);
  Serial.println(3);
  delay(333);
  Serial.println(15);
  delay(333);
  Serial.println(11);
  delay(333);
}

4.938 Beiträge seit 2008
vor 2 Jahren

Der SerialPort hat einen internen Puffer (meist einige KB groß), damit das Programm Zeit hat die Daten einzulesen (und in der Zwischenzeit aber auch neue Daten gesendet werden können).

Dein Code ist so aber noch nicht wirklich einsatzfähig.
Du solltest das DataReceived-Ereignis dafür benutzen (beachte aber, daß dies in einem eigenen Thread läuft, d.h. zur Synchronisation mit dem UI-Thread s. [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke)).

Es gibt aber auch noch das Template SerialPort (wird hier oft empfohlen, habe ich selber aber noch nicht verwendet).

A
AceTecNic Themenstarter:in
51 Beiträge seit 2018
vor 2 Jahren

Alles klar, daher auch die vielen Messergebnisse. Danke! 🙂

Nein, ist er wirklich nicht 😉
Das war jetzt mal der erste Schritt für mich, gibt noch einiges zu tun daran.

Genau, mit dem serialPort1_DataReceived Ereignis hatte ich das auch schon versucht. Aber wie du schon geschrieben hast, habe ich Probleme mit dem Threads. Den Link werde ich mir heute Abend mal anschauen - Danke dafür!

A
AceTecNic Themenstarter:in
51 Beiträge seit 2018
vor 2 Jahren

Guten Morgen,

ich habe mir die Invoke-Sache mal angeschaut und versucht anhand eines Beispiels es nachzubauen.
Allerdings kommt nichts dabei raus. Kannst du mir einen Tipp geben warum es im Beispiel klappt, aber bei mir nicht?

Zu Beginn habe ich die delegate deklariert:


    public partial class Form1 : Form
    {
        public delegate void AddDataDelegate(String meinString);
        public AddDataDelegate meinDelegate;


Im Toolstrip wähle ich den Port aus und öffne ihn mittels Click:


        private void cOMPortToolStripMenuItem_Click(object sender, EventArgs e)
        {
            serialPort1.Close();
            serialPort1.PortName = sender.ToString();
            serialPort1.Open();
        }

Sobald der Port geöffnet ist, sollte doch das Ereignis anfangen zu arbeiten? Ich habe Testhalber mal eine richtextbox ausgewählt wie in dem Beispiel:


        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string bar = serialPort1.ReadExisting();
            richTextBox1.Invoke(this.meinDelegate, new object[] { bar });
            richTextBox1.Clear();
            
            /* Nicht Thread-sicher!
            string bar = serialPort1.ReadExisting();
            label1.BeginInvoke(bar);
            chart_live.Series.Add("Druck ist");
            chart_live.Series[0].ChartType = SeriesChartType.Line;
            chart_live.Series[0].Points.Add(Convert.ToInt32(bar));
            string bar = serialPort1.ReadExisting();
            label1.Text = bar;
            */
        }

16.830 Beiträge seit 2008
vor 2 Jahren

Übersehen, dass Invoke schon da ist

4.938 Beiträge seit 2008
vor 2 Jahren

Das mit dem Delegate scheinst du mißverstanden zu haben. Du kannst als ersten Parameter direkt eine Methode angeben (bei dir müßtest du ja noch meinDelegate mit einer eigenen Methode abonnieren).

Und hinzu kommt, daß richTextBox1.Clear() ja auch wieder ein thread-übergreifender Zugriff wäre (und m.E. hier auch keinen Sinn macht, nach dem Hinzufügen von Daten diese wieder zu löschen!?!).

Einfacher geht es auch mit einem Lambda-Ausdruck (anonyme Methode):


string text = serialPort1.ReadExisting();
Invoke(() => richtextBox1.AppendText(text));