c#串口seralport接收发送数据,生成chart折线图,并保存

刚刚从头开始学习c#,在查询资料过程中,感觉各位大神写的太高深了,这里是我写的一个串口程序,希望与同我一样的小白们一同努力,不要放弃,向更深一步加油吧;

程序要求:与两个串口进行通讯,定时发出数据,对返回的数据进行处理(帧头帧尾识别),经过算法,得到一组数据,并将其输出到chart图表上(折线图),最后保存图表。


以下为代码:

using System;
using System.IO.Ports;
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.Text.RegularExpressions;
using System.Diagnostics;
using System.Timers;
using System.Windows.Forms.DataVisualization.Charting;



namespace 接收完整版
{
 public partial class Form1 : Form
 {
  private SerialPort sp1 = new SerialPort();                //建立串口sp1
  private SerialPort sp2 = new SerialPort();              //建立串口sp2 
  public static double shuchu1;                               //sp1输出数据
  public static double shuchu2;                               //sp2输出数据
  public static double max0 = 0;                             //项目算法中参数
  public static double c;                                          //同上
  public static double d;                                           //同上
  public static int cishu=0;                                        //定时器运行次数
  static System.Timers.Timer t;                                 //定时器声明
  Series series = new Series("Spline");                     //chart图标
  public Form1()
  {
   InitializeComponent();                                          
  }
  private void Form1_Load(object sender, EventArgs e)
  {
   sp1.ReceivedBytesThreshold = 1;       //sp1参数设置,这里是接收1个数据便促发接收处理程序;接下来是串口号,波特率,奇偶位,停止位,数据位数设置;
   sp1.PortName = "COM5";
   sp1.BaudRate = 115200;
   sp1.Parity = Parity.None;
   sp1.StopBits = StopBits.One;
   sp1.DataBits = 8;
   sp1.Open();                                        //sp1串口打开
   sp1.DataReceived += new SerialDataReceivedEventHandler(sp1_DataReceived);   //sp1接收数据事件

   sp2.ReceivedBytesThreshold = 1;     //sp2参数设置
   sp2.PortName = "COM6";
   sp2.BaudRate = 115200;
   sp2.Parity = Parity.None;
   sp2.StopBits = StopBits.One;
   sp2.DataBits = 8;
   sp2.Open();//打开串口
   sp2.DataReceived += new SerialDataReceivedEventHandler(sp2_DataReceived);
   Control.CheckForIllegalCrossThreadCalls = false;                 线程间检测关闭(即跨线程调用不报错)

   chart1.Series.Clear();
   series.ChartType = SeriesChartType.Spline;      //图类型Spline
   chart1.Series.Add(series);                      //添加一个图表序列

   this.chart1.ChartAreas[0].AxisY.Minimum = 0;           //设置设置纵坐标的最小值0
   this.chart1.ChartAreas[0].AxisY.Maximum = 0.2;           //设置设置纵坐标的最大值0.2
   this.chart1.ChartAreas[0].AxisX.Minimum = 0;           //设置设置纵坐标的最小值0
   this.chart1.ChartAreas[0].AxisX.Maximum = 2000;           //设置设置纵坐标的最大值0.2
   this.chart1.ChartAreas[0].AxisX.Interval = 100;          //设置横坐标间隔为50,使得每个刻度间均匀分开的
   this.chart1.ChartAreas[0].AxisY.Interval = 0.01;
   this.chart1.ChartAreas[0].AxisX.MajorGrid.LineColor = System.Drawing.Color.Green;   //背景网格线颜色为银色
   this.chart1.ChartAreas[0].AxisY.MajorGrid.LineColor = System.Drawing.Color.Green;    //背景网格线颜色为银色
   this.chart1.ChartAreas[0].AxisX.Title = "次数/次";              //设置下方横坐标名称
   this.chart1.ChartAreas[0].AxisY.Title = "同轴度/mm";          //设置左边纵坐标的名称
   chart1.ChartAreas[0].Area3DStyle.Enable3D = true;           //以3D形式展示
   
   chart1.Series[0].Color = Color.Red;               //线条颜色

  }
  private List<byte> buffer = new List<byte>(1048576);     //sp1接收事件
  void sp1_DataReceived(object sender, SerialDataReceivedEventArgs e)
  (
   int n = sp1.BytesToRead;//待读字节个数
   byte[] buf = new byte[n];//创建n个字节的缓存
   byte[] ReceiveBytes = new byte[9];
   sp1.Read(buf, 0, n);//读到在数据存储到buf
   //缓存数据
   buffer.AddRange(buf);//不断地将接收到的数据加入到buffer链表中
   while (buffer.Count >= 6) //至少包含帧头(1字节)、数据(3字节)、帧尾(1字节)、效验位(1字节);
   {
    if (buffer[0] == 0x02) //到帧头  02H
    {
     if (buffer.Count < 6) //数据区尚未接收完整,
     {
      break;//跳出接收函数后之后继续接收数据
     }
     //得到完整的数据,复制到ReceiveBytes中进行校验
     buffer.CopyTo(0, ReceiveBytes, 0, 6);//复制数据
     byte check; //开始校验
     check = 0x03;//帧尾
     if (check != ReceiveBytes[4]) //帧尾验证位失败  
     {
      buffer.RemoveRange(0, 6);//从链表中移除接收到的校验失败的数据,
      continue;                //继续执行while循环程序,
     }
 
     buffer.RemoveRange(0, 6);
     string strRcv = null;
     for (int i = 1; i < 4; i++) //窗体显示
     {
      strRcv += ReceiveBytes[i].ToString("X2");  //16进制显示
     }
     //

                项目算法

    //
    }
    else //帧头不正确时,清除
    {
     buffer.RemoveAt(0);//清除第一个字节,继续检测下一个。
    }
   }
  }

  private List<byte> buffer2 = new List<byte>(1048576);     //sp2接收事件
  void sp2_DataReceived(object sender, SerialDataReceivedEventArgs e)
  {
   int n = sp2.BytesToRead;//待读字节个数
   byte[] buf2 = new byte[n];//创建n个字节的缓存
   byte[] ReceiveBytes2 = new byte[11];
   sp2.Read(buf2, 0, n);//读到在数据存储到buf
   //缓存数据
   buffer2.AddRange(buf2);//不断地将接收到的数据加入到buffer链表中
   while (buffer2.Count >= 9) //至少包含帧头(1字节)、数据(7字节)、帧尾(1字节);
   {
    if (buffer2[0] == 0x02) //到帧头  02H
    {
     if (buffer2.Count < 9) //数据区尚未接收完整,
     {
      break;//跳出接收函数后之后继续接收数据
     }
     //得到完整的数据,复制到ReceiveBytes中进行校验
     buffer2.CopyTo(0, ReceiveBytes2, 0, 9);//
     byte check2; //开始校验
     check2 = 0x03;
     if (check2 != ReceiveBytes2[8]) //帧尾验证位失败  
     {
      buffer2.RemoveRange(0, 9);//从链表中移除接收到的校验失败的数据,
      continue;                //继续执行while循环程序,
     }

     buffer2.RemoveRange(0, 9);
     char[] c = new char[9];
     int a;
     for (int i = 1, j = 0; i < 8; i++, j++)
     {
      a = Convert.ToInt32(ReceiveBytes2[i]);
      c[j] = Convert.ToChar(a);
     }
     string b = new string(c);
     txb2.Text = b;
     shuchu2 = float.Parse(b);
    }
    else                                                       //帧头不正确,清除
    {
     buffer2.RemoveAt(0);                                   //清除第一个字节,继续检测下一个。
    }

   }
  }
  private void button1_Click(object sender, EventArgs e)              //点击开始按钮触发时间;这里需要取初值;
  {
   System.Timers.Timer t0 = new System.Timers.Timer(50);           //实例化Timer类,设置间隔时间为50毫秒;  
   t0.Elapsed += new System.Timers.ElapsedEventHandler(theout0);     //到达时间的时候执行事件;  
   t0.AutoReset = false;                                             //设置是执行一次(false)还是一直执行(true);  
   t0.Enabled = true;                                               //是否执行System.Timers.Timer.Elapsed事件; 
  }
  public void theout0(object source, System.Timers.ElapsedEventArgs e)  //到达时间的时候执行事件;
  {
   string strFrame = "024D3F0371";                                  //sp1 发送单次读取指令;
   byte[] hFrame = new byte[strFrame.Length / 2];
   for (int i = 0; i < strFrame.Length / 2; i++)
   {
    hFrame[i] = Convert.ToByte(strFrame.Substring(i * 2, 2), 16);    //数据格式转换
   }
   sp1.Write(hFrame, 0, 5);

   string strFrame2 = "024D454153555245204103";                    //sp2 发送单次读取指令;
   byte[] hFrame2 = new byte[strFrame2.Length / 2];
   for (int i = 0; i < strFrame2.Length / 2; i++)
   {
    hFrame2[i] = Convert.ToByte(strFrame2.Substring(i * 2, 2), 16);
   }
   sp2.Write(hFrame2, 0, 11);

      t = new System.Timers.Timer(20);           //实例化Timer类,设置间隔时间为20毫秒;  
      t.Elapsed += new System.Timers.ElapsedEventHandler(theout);     //到达时间的时候执行事件;  
   t.AutoReset = true;                                             //设置是执行一次(false)还是一直执行(true);  
   t.Enabled = true;                                               //是否执行System.Timers.Timer.Elapsed事件; 

        }


  public void theout(object source, System.Timers.ElapsedEventArgs e)  //到达时间的时候执行事件;
  {
   cishu = cishu + 1;

   string strFrame = "024D3F0371";                                  //sp1 发送单次读取指令;
   byte[] hFrame = new byte[strFrame.Length / 2];
   for (int i = 0; i < strFrame.Length / 2; i++)
   {
    hFrame[i] = Convert.ToByte(strFrame.Substring(i * 2, 2), 16);
   }
   sp1.Write(hFrame, 0, 5);

   string strFrame2 = "024D454153555245204103";                    //sp2 发送单次读取指令;
   byte[] hFrame2 = new byte[strFrame2.Length / 2];
   for (int i = 0; i < strFrame2.Length / 2; i++)
   {
    hFrame2[i] = Convert.ToByte(strFrame2.Substring(i * 2, 2), 16);
   }
   sp2.Write(hFrame2, 0, 11);
  
   double max;                                                                                        //项目需要的算法,不用管它
   max = System.Math.Abs((shuchu1 - c) + (shuchu2 - d));

   txb32.Text  = max.ToString("0.0000") ;
   if (shuchu1 != 0)                                   
   {
    if(shuchu2 !=0)
    {
           if (max > max0)
      {
                         max0 = max;
         };
     
      txb6.Text = max0.ToString("0.000");
 
       txb31.Text = cishu.ToString("0");

                series.Points.AddXY(cishu, max);                                             //生成图表,因为实时生成会卡,所以这里接收完数据后,一起生成
                }
   }
  }
   private void button2_Click(object sender, EventArgs e)         //暂停键                      
  {  
   t.Stop();
   chart1.Series[0].Points.Clear();
   Application.Exit();
  }
  private void button3_Click(object sender, EventArgs e)                //停止键
  {
      t.Stop();
   sp1.Close();
   sp2.Close();
  }
  private void button4_Click(object sender, EventArgs e)               //待测品放置完成后,读取初值
  {
   string strFrame = "024D3F0371";                                  //sp1 发送单次读取指令;
   byte[] hFrame = new byte[strFrame.Length / 2];
   for (int i = 0; i < strFrame.Length / 2; i++)
   {
    hFrame[i] = Convert.ToByte(strFrame.Substring(i * 2, 2), 16);
   }
   sp1.Write(hFrame, 0, 5);


   string strFrame2 = "024D454153555245204103";                    //sp2 发送单次读取指令;
   byte[] hFrame2 = new byte[strFrame2.Length / 2];
   for (int i = 0; i < strFrame2.Length / 2; i++)
   {
    hFrame2[i] = Convert.ToByte(strFrame2.Substring(i * 2, 2), 16);
   }
   sp2.Write(hFrame2, 0, 11);

   //

      项目中输出显示到textbox

 //
  }
 
  private void button5_Click(object sender, EventArgs e)                  //重置即停止并清楚现有数据
  {
      t.Stop();
   chart1.Series[0].Points.Clear();
   sp1.Close();
   sp2.Close();
   sp1.Open();
   sp2.Open();
   max0 = 0;
   txb6.Text = max0.ToString("0.000");
   cishu = 0;
   txb31.Text = cishu.ToString("0");
  }

  private void btn6_Click(object sender, EventArgs e)                     //保存图像至C:/Users/Administrator/Desktop/同轴度
  {
   DateTime d = DateTime.Now;                                                       //读取当前时间,作为图像保存名称
   string fileName = d.ToString("yyyyMMddHHmmss");                     //将时间转为字符串,并去掉空格,冒号等
   string GR_Path = @"C:/Users/Administrator/Desktop/同轴度/同轴度图像";        
   string fullFileName = GR_Path + "\\" + fileName + ".jpeg";
   chart1.SaveImage(fullFileName, ChartImageFormat.Jpeg);
   chart1.SaveImage("C:/Users/Administrator/Desktop/同轴度/同轴度图像.jpeg", ChartImageFormat.Jpeg);
                                                                                                     //保存图像路径:桌面/同轴度/同轴度图像.jpeg
  }
 }
}

源代码地址:https://download.csdn.net/download/yunsongblue/10277693


  • 5
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先,你需要设置串口的参数,包括波特率、数据位、停止位和校验位等,以便正确接收数据。然后,你可以使用SerialPort类的DataReceived事件来接收串口数据。在事件处理程序,你可以把接收到的数据转化为数字,并将其添加到Chart控件。 下面是一个示例代码: ```csharp using System; using System.IO.Ports; using System.Windows.Forms.DataVisualization.Charting; public partial class Form1 : Form { private SerialPort serialPort; public Form1() { InitializeComponent(); serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One); serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); serialPort.Open(); } private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string data = sp.ReadExisting(); if (data.Length >= 9) { string valueStr = data.Substring(0, 9); double value = Convert.ToDouble(valueStr); this.Invoke((MethodInvoker)delegate { chart1.Series[0].Points.AddY(value); }); } } } ``` 在上面的代码,我们在构造函数初始化了SerialPort类,并将其打开。然后,我们在DataReceivedHandler事件处理程序接收串口数据,并将其转化为数字,并将其添加到Chart控件的Series。需要注意的是,由于串口数据接收是在另一个线程进行的,因此我们需要使用Invoke方法来确保Chart控件的更新是在UI线程进行的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值