最近學習用C#寫了一個串口測驗軟體,從串口接收資料,并將資料繪制成波形圖,在實際程式中使用的控制元件是chart(measurement studio2015中的waveformgraph不是很好用)測驗時發現,chart在繪制了1000-2000個資料點之后,程式運行會出現例外,當我注釋了向chart添加資料的函式之后,運行沒有例外發生。
例外提醒是 : “System.InvalidOperationException”型別的未經處理的例外在System.Windows.Forms.DataVisualization.dll中發生。
不知道各位有沒有好的解決辦法。
例外貼圖與代碼如下:

代碼如下:
using System;
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.Runtime.InteropServices;
using System.Windows.Forms.DataVisualization.Charting;
using System.IO;
using System.IO.Ports;
using NationalInstruments;
//using NationalInstruments.Controls.Data;
namespace HRM200Test
{
public partial class Form1 : Form
{
int Timercount = 0;//用于定時器計數
byte[] gDataToSend = new byte[2] { 0x00, 0x00 }; //資料發送
public Form1()
{
InitializeComponent();
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
// timer1.Start();
}
internal class flagclass
{
public static int button1_click_flag = 0 ;
public static int button4_click_flag = 0 ;
public static int button5_click_flag = 0;
public static int PCR_Run_flag = 0;
public static int StepCnt = 0;
public static int LoopCnt = 0;
public static int TimeValue = 0;
public static int Predegeneration_flag = 0;
public static int DaRxCnt = 0 ;
public static byte[] DataRxBuf = new byte[50];
public static byte[] TemperByte = new byte[5];
}
private void button1_Click(object sender, EventArgs e)
{
if (flagclass.button1_click_flag == 0)
{
try
{
serialPort1.PortName = comboBox1.Text;
serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text,10);//十進制資料轉換
serialPort1.Open();
flagclass.button1_click_flag = 1;
button1.BackColor = SystemColors.ActiveCaption;
button1.Text = "關閉串口";
}
catch
{
MessageBox.Show("埠錯誤,請檢查串口", "錯誤");
}
}
else
{
try
{
serialPort1.Close();//關閉串口
button1.Text = "打開串口";
button1.Enabled = true;//打開串口按鈕可用
button1.BackColor = SystemColors.InactiveBorder;
flagclass.button1_click_flag = 0;
}
catch (Exception)//Exception err)//一般情況下關閉串口不會出錯,所以不需要加處理程式
{
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
SearchAndAddSerialToComboBox(serialPort1, comboBox1);
comboBox2.SelectedIndex = 3;
button4.Enabled = false;
ChartInit();
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int LEN = 50;
Int16 i = 0;
float[] fdata = new float[4] ;
byte[] crcvalue = new byte[2] { 0x00, 0x00 };
byte[] buffer1 = new byte[LEN];
int[] buf1 = new int[100];
LEN = 0;
LEN = serialPort1.BytesToRead;
serialPort1.Read(buffer1, 0, LEN);
if (buffer1[0] == 0x41 && buffer1[1] == 0x04 && CRC16_2(buffer1)[0] == buffer1[18] && CRC16_2(buffer1)[1] == buffer1[19])
{
for (int j = 0; j < 4; j++)
{
flagclass.TemperByte[3] = buffer1[j * 4 + 2];
flagclass.TemperByte[2] = buffer1[j * 4 + 3];
flagclass.TemperByte[1] = buffer1[j * 4 + 4];
flagclass.TemperByte[0] = buffer1[j * 4 + 5];
fdata[j] = BitConverter.ToSingle(flagclass.TemperByte, 0) ;
}
try
{
chart2.Series[0].Points.AddY( fdata[1]);
textBox11.Text = fdata[1].ToString();
if ( (chart2.ChartAreas[0].AxisX.Maximum - chart2.ChartAreas[0].AxisX.Minimum) >= 1024)
chart2.ChartAreas[0].AxisX.Minimum = chart2.ChartAreas[0].AxisX.Maximum - 1024;
}
catch {
MessageBox.Show(" error!","zzZ");
}
}
else
{
string str1 = System.Text.Encoding.Default.GetString(buffer1); //buffer1.ToString();
textBox1.AppendText(str1);//添加內容
textBox1.Text.ToArray();
}
}
private void SendDataToSerialPort(SerialPort MyPort, byte[] DataToSend) //單位元組發送資料
{
const byte Nlen = 0x07 ;
byte[] crcvalue = new byte[2] { 0x00, 0x00 };
crcvalue[0] = CRC16(DataToSend)[0];
crcvalue[1] = CRC16(DataToSend)[1];
byte[] DatasToWrite = new byte[Nlen] { 0x54 , DataToSend[0], DataToSend[1], crcvalue[0], crcvalue[1], 0x0D ,0x0A }; //資料包
if (serialPort1.IsOpen)
{
try
{
// MyPort.WriteLine("");
MyPort.Write(DatasToWrite, 0, Nlen); //發資料
}
catch
{
MessageBox.Show("串口資料寫入錯誤", "錯誤");
}
}
}
private void SearchAndAddSerialToComboBox(SerialPort MyPort, ComboBox MyBox)
{ //將可用埠號添加到ComboBox
string Buffer; //快取
MyBox.Items.Clear(); //清空ComboBox內容
for (int i = 1; i < 40; i++) //回圈
{
try //核心原理是依靠try和catch完成遍歷
{
Buffer = "COM" + i.ToString();
MyPort.PortName = Buffer;
MyPort.Open(); //如果失敗,后面的代碼不會執行
MyBox.Items.Add(Buffer); //打開成功,添加至下倆串列
MyPort.Close(); //關閉
}
catch
{
}
}
}
public static byte[] CRC16(byte[] data )//string sInputString)
{
int len = data.Length;
if (len > 0)
{
ushort crc = 0xFFFF;
for (int i = 0; i < len; i++)
{
crc = (ushort)(crc ^ (data[i]));
for (int j = 0; j < 8; j++)
{
crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
}
}
byte hi = (byte)((crc & 0xFF00) >> 8); //高位置
byte lo = (byte)(crc & 0x00FF); //低位置yindu
return new byte[] { hi, lo };
}
return new byte[] { 0, 0 };
}
public static byte[] CRC16_2(byte[] data)//string sInputString)
{
// byte[] data = System.Text.ASCIIEncoding.ASCII.GetBytes(sInputString);
int len = 18;
if (len > 0)
{
ushort crc = 0xFFFF;
for (int i = 2; i < len; i++)
{
crc = (ushort)(crc ^ ( (byte) data[i]));
for (int j = 0; j < 8; j++)
{
crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
}
}
byte hi = (byte)((crc & 0xFF00) >> 8); //高位置
byte lo = (byte)(crc & 0x00FF); //低位置yindu
return new byte[] { hi, lo };
}
return new byte[] { 0, 0 };
}
// ASCII碼轉為字串
public static string ByteToString(byte[] arr, bool isReverse)
{
try
{
byte hi = arr[0], lo = arr[1];
return Convert.ToString(isReverse ? hi + lo * 0x100 : hi * 0x100 + lo, 16).ToUpper().PadLeft(4, '0');
}
catch (Exception ex) {
MessageBox.Show("123", "錯123誤");
throw (ex); }
}
private void button3_Click(object sender, EventArgs e)
{
textBox1.Text = "";
}
private void button2_Click(object sender, EventArgs e)
{
// MessageBox.Show("正在掃描,請等待...");
SearchAndAddSerialToComboBox(serialPort1, comboBox1);
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);//必須手動添加事件處理程式
MessageBox.Show(" 掃描完成!", "提示");
}
private void ChartInit()
{
chart2.Series[0].Points.Add(0);
chart2.Series[0].Color = Color.Red;
chart2.ChartAreas[0].AxisY.Minimum = 0;
chart2.ChartAreas[0].AxisY.Maximum = 100;
chart2.ChartAreas[0].AxisY.Interval = 10;
chart2.ChartAreas[0].AxisX.MajorGrid.LineDashStyle = ChartDashStyle.Dash;//網格刻線為虛線、白色
chart2.ChartAreas[0].AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dash;//網格刻線為虛線、白色
chart2.ChartAreas[0].AxisX.LineDashStyle = ChartDashStyle.Solid;//坐標軸 為實線
chart2.ChartAreas[0].AxisY.LineDashStyle = ChartDashStyle.Solid;//坐標軸 為實線
}
}
}
uj5u.com熱心網友回復:
回圈操作集合的同時,對集合中的元素有移除或者添加添加操作導致的。具體需要你定位到出錯回圈。uj5u.com熱心網友回復:
就是這句“chart2.Series[0].Points.AddY( fdata[1]); ”,注釋掉沒事了,但也不顯示波形了。
uj5u.com熱心網友回復:
而且我也沒有在回圈中使用 System.Windows.Forms.DataVisualization.dll 中的類或函式呀?
uj5u.com熱心網友回復:
并發操作同一個變數 就會出來這種問題.lock一下 應可以解決
uj5u.com熱心網友回復:
我把下面的if()這句注釋掉之后,就只剩下上面這句和chart相關的陳述句了,測驗了幾次還沒有出現過發生在System.Windows.Forms.DataVisualization.dll中的例外。if陳述句作用是讓chart顯示固定的資料量,不然chart上的曲線會堆集在一起,不能分辨了。請問各位大佬有什么好的方法解決這個問題?
chart2.Series[0].Points.AddY( fdata[1]);
textBox11.Text = fdata[1].ToString();
if ( (chart2.ChartAreas[0].AxisX.Maximum - chart2.ChartAreas[0].AxisX.Minimum) >= 1024)
chart2.ChartAreas[0].AxisX.Minimum = chart2.ChartAreas[0].AxisX.Maximum - 1024;
uj5u.com熱心網友回復:
接收資料 serialPort1_DataReceived 方法不是運行在 UI 執行緒,在這個方法中不能直接修改 UI 執行緒的 Chart 控制元件。凡是這類情況,應在接收資料的執行緒里處理資料,生成資料源,最后使用 this.Invoke 方法呼叫 UI 執行緒的更新方法來更新 Chart,避免接收資料的執行緒與 UI 執行緒同時操作 Chart 造成錯誤。uj5u.com熱心網友回復:
懂了,明天把這兩部分分開寫,試試看效果。今天下午有事,暫時測不了。thx.
uj5u.com熱心網友回復:
對陣列物件回圈的時候,不要去修改物件本身。uj5u.com熱心網友回復:
我異步用chart畫折線圖的時候也有這個問題,后面我把集合資料從大到小遍歷就好了
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/99220.html
標籤:C#
下一篇:在線請幫忙解決
