我正在从串口读取数据值,并使用调用和委托在zedgraph控件上实时绘制数据。我想点击一个断开按钮,这将停止绘图,当一个连接按钮被按下,绘图将继续。我的问题是当我重新连接时,绘图将不会以每秒1点的速度显示。会有意想不到的行为,有时包括延迟,不会规划2秒,下一秒,它将绘制2分在同一时间。有时它不会绘制3秒和下一个秒,它会同时绘制3分,有时它会很好地绘制1分每秒。有时,它会以每秒两次或三次的速度进行绘制。只有当我断开连接,然后重新连接时,才会出现此问题。我的GUI响应也开始变得更糟,每次我断开和重新连接,直到最后没有响应。
当我单击“断开”时,我会清除zedgraph,但不要关闭串行端口。当我再次单击connect时,串口将再次开始发送数据并继续绘制,每次在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标志来启动和停止绘图。任何帮助都是非常感谢的!提前感谢!
发布于 2014-05-03 21:11:32
调用txtUSBLoad.Invoke()将处理切换到GUI线程(用于处理用户输入和绘制控件的同一个线程)。通过将所有处理放入调用调用()中,您实际上是在淹没GUI线程。
如果您的串行更新足够频繁,这将导致交互/重新绘制GUI的延迟。
这里有几个选项,第一件事是将所有处理保留在从串口接收消息的线程中。查看正在更新的所有可视控件,确定它们需要更新的数据,并在调用Invoke()之前处理这些数据。创建一个类来保存数据。
这可能太慢了,这意味着您将积累大量无法及时处理的串行数据。如果是这样的话,您可以将传入的数据混为一谈,如果您认为丢失更新没有问题的话。你得看看这是否适用于你的情况。
如果您想尝试并并行处理传入的数据,请查看TPL数据流中如何为数据创建处理管道的示例。
https://stackoverflow.com/questions/23449745
复制相似问题