最近学习用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;//坐标轴 为实线
        
        }    }
}

解决方案 »

  1.   


    就是这句“chart2.Series[0].Points.AddY( fdata[1]); ”,注释掉没事了,但也不显示波形了。
      

  2.   


    而且我也没有在循环中使用 System.Windows.Forms.DataVisualization.dll 中的类或函数呀?
      

  3.   

    并发操作同一个变量 就会出来这种问题.lock一下 应可以解决
      

  4.   

    我把下面的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;
      

  5.   

    接收数据 serialPort1_DataReceived 方法不是运行在 UI 线程,在这个方法中不能直接修改 UI 线程的 Chart 控件。凡是这类情况,应在接收数据的线程里处理数据,生成数据源,最后使用 this.Invoke 方法调用 UI 线程的更新方法来更新 Chart,避免接收数据的线程与 UI 线程同时操作 Chart 造成错误。
      

  6.   


    懂了,明天把这两部分分开写,试试看效果。今天下午有事,暂时测不了。thx.
      

  7.   


    我异步用chart画折线图的时候也有这个问题,后面我把集合数据从大到小遍历就好了