C# 接收串口数据并利用GDI+绘制波形图

前言:

       这里是我的第一篇博文,记录一个菜鸟的成长之路。接触C#还是在学校的实验室里,第一个程序就是为了配合单片机写的简单的串口助手,另外还有移植的四旋翼地面站,还有基于TCP/IP协议的本地服务器。一直没有好好总结一下,但是值得自己骄傲的事情就是,一直在学习的路上~

       说到C#,还是看中了它开发的简洁方便,其实并没有深入进去,但是做出来的小东西还是比较可人的,不是纯技术分享,而是将自己做过的小玩意写下来,一是记录,二是万一帮到别人呢?有不对的地方请不吝指正,转载请注明出处~

工具:VS2015,下载地址请点我

主要内容有:

C#传输串口数据

        用C#做一个串口接收和发送的程序还是比较容易的,因为它封装了serialPort,在Designer 直接添加就好啦~添加完成后设置波特率,停止位,数据位等等,设置完成后,这个接口的雏形也就出来啦。

        首先,要打开端口。

 try//btn打开端口
            {
                serialPort1.PortName = comboBox1.Text;
                serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);
                serialPort1.Open();
                button1.Enabled = false;//改变按钮状态
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString(), "系统提示");
            }

下面就是对接收的数据进行处理啦。

            if (radioButton4.Checked)//如果文本方式被选中,添加的radioButton控件
            {
                byte[] readBuffer = new byte[serialPort1.ReadBufferSize];
                serialPort1.Read(readBuffer, 0, readBuffer.Length);
                string readstr = Encoding.UTF8.GetString(readBuffer);
                richTextBox1.Text += readstr;//这个+= 是一直往容器添加而不是替换
                string strr = readstr;
                string[] sArray = strr.Split(',');
                chache = int.Parse(sArray[A.Channel]);//A.Channel表示数组的元素位置0/1/2/3
                textBox1.Text = Test_Value.ToString();


             else//十六进制模式
            }
            else
            {
                try
                {
                    byte[] data = new byte[serialPort1.BytesToRead];//定义缓冲区,因为串口事件触发时有可能收到不止一个字节
                    serialPort1.Read(data, 0, data.Length);
                    foreach (byte Member in data)
                    {
                        string str = Convert.ToString(Member, 16).ToUpper();
                        richTextBox1.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " ");
                    }
                }
                catch (Exception err)//这里可以将异常打印到弹出的窗口中
                {
                    MessageBox.Show(err.ToString(), "系统提示");
                }
            }

以上就是串口数据的接收函数啦,发送函数在下方。

                    if (!radioButton1.Checked)//选择数据格式
                    {
                        try
                        {
                            serialPort1.Write(richTextBox2.Text);
                        }
                        catch (Exception err)
                        {
                            MessageBox.Show(err.ToString(), "系统提示");
                        }
                    }
                    else
                    {
                        try
                        {
                            for (int i = 0; i < (richTextBox2.Text.Length - richTextBox2.Text.Length % 2) / 2; i++)//转换偶数个
                            {
                                Data[0] = Convert.ToByte(richTextBox2.Text.Substring(i * 2, 2), 16);           //转换
                                serialPort1.Write(Data, 0, 1);
                            }
                            if (richTextBox2.Text.Length % 2 != 0)
                            {
                                Data[0] = Convert.ToByte(richTextBox2.Text.Substring(richTextBox2.Text.Length - 1, 1), 16);//单独处理最后一个字符
                                serialPort1.Write(Data, 0, 1);
                            }
                        }
                        catch (Exception err)
                        {
                            MessageBox.Show(err.ToString(), "系统提示");
                        }
                    }
                }
            }

以上就是串口的处理代码了~接下来绘制图表,是个问题!第一个想到的就是利用vs提供的chart控件来实现数据的绘制,但是,遇到的问题是:数据量大了之后,窗口滑动不成功,再就是接收数据造成的阻塞问题!当然了,这是我没有解决掉的问题!所以,还是采用毕业设计所用的GDI+绘图,虽然条条框框都需要自己绘制,但是还是比较稳定的呀!

 这是我的程序中所有的引用:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Drawing2D;
using MathWorks.MATLAB.NET.Arrays;

看到了,还有一个 using MathWorks.MATLAB.NET.Arrays;嗯~ o(* ̄▽ ̄*)o这是刚get到的C# + Matlab混合编程的点,我掌握了方法之后会第一时间将方法奉上!

GDI+绘图首先要做的就是添加一个Picturebox控件,然后把画布绘制在上面!之后就是设置各种凌乱的参数,比如:


        Graphics waveform;//封装一个GDI+绘图图面
        //创建原点坐标(有序数对)
        Point Origin;
        int Original_X;//X值
        int Original_Y;//Y值
        //创建X轴顶点坐标(有序数对)
        Point Top_X;
        //创建X轴顶点坐标(有序数对)
        Point Top_Y;
        //X轴长度(单位:像素)
        int LengthX;
        int LengthY;
        //设置坐标轴颜色轴变量
        Color colorPen;      //曲线上标记的数字
        Color CoordinateAxis;//坐标轴
        Color AxisFlagColor; //偏移量(字)
        //设置轴的刻度数
        int BlocksX = 15; 
        int BlocksY = 16; 

如果想做测试的话,这里有个随机数发生器:

        Random r;       //伪随机数生成器
        List list; //可检索的列表
        int seed;  //种子变量
          list = new List();//初始化List实例
          r = new Random();//初始化伪随机数容器
          for (int i = 0; i < 100; i++)//添加随机数到List结尾
          {
              list.Add(r(seed));
          }

窗口滑动的关键:

        private void ChangeList()
        {
            list.RemoveAt(0);
            list.Add(r(seed));
        }

准备工作都差不多了,开始绘制画布吧!


            waveform = e.Graphics; //使用封装过的 GDI+ 绘图
            waveform.SmoothingMode = SmoothingMode.HighQuality;//平滑处理,高品质
            Pen Axis = new Pen(CoordinateAxis, 1);//创建绘制坐标轴的画笔
            Axis.EndCap = LineCap.ArrowAnchor;//坐标轴结尾形状 箭头 
            Top_Y = new Point(Original_X, Original_Y - LengthY);  //计算Y轴顶点坐标 (X="0",坐标系原点Y值 - Y长度),由于屏幕左上为(0,0),所以要处理成负数
            Top_X = new Point(Original_X + LengthX, Original_Y);  //计算X轴顶点坐标 (坐标系原点X值 + X长度,Y="0")
            Origin = new Point(Original_X, Original_Y);//原点(有序数对)
            waveform.DrawLine(Axis, Origin, Top_X);//绘制X轴
            waveform.DrawLine(Axis, Origin, Top_Y);//绘制Y轴

            int Cell_X = LengthX / BlocksX;    
            int Cell_Y = LengthY / BlocksY;   

            Pen AxisFlag = new Pen(AxisFlagColor, 1);
            AxisFlagBrush = new SolidBrush(AxisFlagColor);
            //Y轴刻度、游标绘制
            for (int i = 0; i <= BlocksY; i++)
            {                
                waveform.DrawLine(AxisFlag, new Point(Original_X, Original_Y - i * (Cell_Y - 1)), new Point(Original_X - 3, Original_Y - i * (Cell_Y - 1)));
                if (i * 10 >= 100)//游标
                {
                    waveform.DrawString((i * 257).ToString(), AxisFont, AxisFlagBrush, new Point(Original_X - 30, Original_Y - i * (Cell_Y - 1) - 8));
                }                         
                else
                {
                    waveform.DrawString((i * 257).ToString(), AxisFont, AxisFlagBrush, new Point(Original_X - 27, Original_Y - i * (Cell_Y - 1) - 8));
                }                   
            }
            //X轴刻度、游标绘制
            for (int j = 0; j <= BlocksX; j++)   //可以根据需要调整疏密
            {             
                waveform.DrawLine(AxisFlag, new Point(Original_X + j * Cell_X, Original_Y), new Point(Original_X + j * Cell_X, Original_Y + 3));
                //       17为一个单位                                 
                waveform.DrawString((j * 1.488).ToString(), AxisFont, AxisFlagBrush, new Point(Original_X + j * Cell_X - 5-10, Original_Y + 5));
            }                                                                        
            Axis.Dispose();//释放画笔资源
            DrawWave(e);   //调用绘制函数,下方的代码就是啦

 如果画布绘制完成了的话,绘图工作就已经完成一大半了,毕竟绘制图形的方式和绘制画布的方式是一样的!

for (int i = 0; i < list.Count - 1; i++) //数据包含在列表内
            {                     
                Point sp = new Point(Original_X + i * 2, Original_Y - list[i]);
                ep = new Point(Original_X + (i + 1) * 2, Original_Y - list[i + 1]);
                g.DrawLine(Pens.DarkGreen, sp, ep);
            }

以上。

 

你可能感兴趣的:(C#,C#,GDI+)