【问题标题】:Delay in Plotting Data from a Serial Port using Control.Invoke and Delegates使用 Control.Invoke 和 Delegates 从串行端口绘制数据的延迟
【发布时间】:2014-05-03 20:56:27
【问题描述】:

我正在从串行端口读取数据值,并使用调用和委托在 zedgraph 控件上实时绘制数据。我想单击将停止绘图的断开按钮,当按下连接按钮时,绘图将恢复。我的问题是当我重新连接时,绘图不会以每秒 1 点的速度显示。会出现意想不到的行为,有时会出现 2 秒内不绘制的延迟,而下一秒它将同时绘制 2 个点。有时它不会在 3 秒和下一秒绘制,它会同时绘制 3 个点,有时它会正常绘制每秒 1 个点。有时它会每秒绘制两次或三次。仅当我断开连接然后重新连接时才会出现此问题。每次断开连接并重新连接时,我的 GUI 响应也开始变得更糟,直到最终没有响应。

当我单击断开连接时,我清除了 zedgraph 但不关闭串行端口。当我再次单击连接时,串行端口将再次开始发送数据并继续绘图,每次在 zedgraph 上绘制新数据点时调用 control.invoke。我调用调用的问题是否太多次,我将如何解决这个问题?我需要实时绘图,所以每次收到数据点时,立即将其绘制在 zedgraph 上。

这是我连接到串行端口的方式:

private void btnConnect_Click_1(object sender, EventArgs e)
    {
        curveUSB = myPaneUSB.AddCurve("Load", listUSB, Color.Black, SymbolType.Circle);
        isConnected = true;

        DateTime startTime = DateTime.Now;
        txtStartTime.Text = startTime.ToString();
        sw.Start();
        createCSVFile(startTime);

        try
        {
            if (!serialPort1.IsOpen)
            {

                serialPort1.PortName = cmbPort.Items[cmbPort.SelectedIndex].ToString();


                //Other Serial Port Property
                serialPort1.Parity = Parity.None;
                serialPort1.StopBits = StopBits.One;
                serialPort1.DataBits = 8;
                serialPort1.BaudRate = 9600;
                //Open our serial port
                serialPort1.Open();
            }
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.Message);
        }



        Thread.Sleep(100); //Always sleep before reading
        serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceivedHandler);

        // Save the beginning time for reference
        tickStart = Environment.TickCount;  //used the calculate the time 
        setGraphAxis(myPaneUSB, zgControlUSB);
        //Disable Connect button
        btnConnect.Enabled = false;
        //Enable Disconnect button
        btnDisconnect.Enabled = true;        
    }

调用和serialPort1_DataReceivedHandler:

private void serialPort1_DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
    {
        if (isConnected == true)
        {
            txtUSBLoad.Invoke(new EventHandler(delegate
            {

                strRawData = serialPort1.ReadLine();

                txtUSBLoad.Text = strRawData + loadUnit;
                Display_Data(strRawData, curveUSB, listUSB, zgControlUSB);


            }));
        }
    }

Display_Data 函数显示绘图:

private void Display_Data(String data, LineItem curve, IPointListEdit list, ZedGraphControl zgControl) 
    {

        ts = sw.Elapsed;
        tsBT = swBT.Elapsed;
        elapsedTime = String.Format("{0:00}:{1:00}:{2:00}",tsBT.Hours, tsBT.Minutes, tsBT.Seconds);
        elapsedTimeBT = String.Format("{0:00}:{1:00}:{2:00}", tsBT.Hours, tsBT.Minutes, tsBT.Seconds);
        txtElapsedTime.Text = elapsedTime;
        txtBTElapsedTime.Text = elapsedTimeBT;


        if (zgControl.GraphPane.CurveList.Count <= 0)                    //Make sure that the curvelist has at least one curve
            return;
        curve = zgControl.GraphPane.CurveList[0] as LineItem;            //Get the first CurveItem in the graph
        if (curve == null)
            return;
        list = curve.Points as IPointListEdit;                                  //Get the PointPairList
        if (list == null)                                                       //If this is null, it means the reference at curve.Points does not
            return;                                                             //support IPointListEdit, so we won't be able to modify it
        time = (Environment.TickCount - tickStart) / 1000.0;             //Time is measured in seconds
                                             //Get current time        
        now = DateTime.Now;
        timestamp = now.ToOADate();
        list.Add(timestamp, Convert.ToDouble(data)); 
        if(fileWriter.BaseStream != null){  //If fileWriter is open, then write to file, else don't write
            fileWriter.WriteLine(String.Format("{0:yyyy-MM-dd_HH-mm-ss}", now) + "," + data);   //writes the timestamp and data to the CSV file
        }
        if (Convert.ToDouble(data) > tempLoad)  //Checks if the current load is the maximum load
        {
            tempLoad = Convert.ToDouble(data);
            txtMaxLoad.Text = tempLoad.ToString() + " " + loadUnit;
            txtBTMaxLoad.Text = tempLoad.ToString() + " " + loadUnit;
        }
        //if ((Convert.ToDouble(data) > dblThreshold) && (emailAlerts == true)) { 
        if ((Convert.ToDouble(data) > 50) && (emailAlerts == true))
        { 
            sendEmail(Convert.ToDouble(data));
        }

        XDate dateTime = curve[0].X;                                   

        zgControl.AxisChange();                                          //changes the x-axis  
        zgControl.Invalidate();                                          //Force a redraw
    }

断开按钮:

 private void btnDisconnect_Click_1(object sender, EventArgs e)
    {
        zgControlUSB.GraphPane.CurveList.Clear();
        if (fileWriter != null)
        {
            fileWriter.Close(); 
        }
        isConnected = false;
        btnConnect.Enabled = true;
        btnDisconnect.Enabled = false;
        txtUSBLoad.Text = initText;
        DateTime endTime = DateTime.Now;
        txtEndTime.Text = endTime.ToString();   //displays the time stamp when the plotting stops
        sw.Stop();  //stops the stop watch 

    }

当我断开连接时,我不会关闭串行端口,因为这样做时问题会更糟,而且我读到总是关闭并重新打开串行端口是不好的。相反,我使用 isConnected 标志来开始和停止绘图。 任何帮助表示赞赏!提前致谢!

【问题讨论】:

标签: c# serial-port zedgraph


【解决方案1】:

调用 txtUSBLoad.Invoke() 会将处理切换到 GUI 线程(用于处理用户输入和绘制控件的同一线程)。通过把所有的处理放在调用 Invoke() 你实际上淹没了 GUI 线程。

如果您的连续更新足够频繁,这将导致延迟交互/重新绘制 GUI。

这里有几个选项,第一件事是将所有处理保留在从串口接收消息的线程中。查看您正在更新的所有可视控件,并确定它们需要更新哪些数据,并在调用 Invoke() 之前处理尽可能多的数据。创建一个类来保存数据。

这可能太慢了,这意味着您将积压大量无法及时处理的串行数据。如果是这样,如果您同意丢失更新,您可以合并传入的数据。你必须看看这是否适用于你的情况。

如果您想尝试并行处理传入数据,请查看TPL Dataflow,了解如何为数据创建处理管道的示例。

【讨论】:

    猜你喜欢
    • 2011-08-02
    • 1970-01-01
    • 1970-01-01
    • 2019-03-03
    • 1970-01-01
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    相关资源
    最近更新 更多