C#实现串口通讯实时显示波形并实现平滑滤波和50Hz滤波

     实现单片机与电脑通讯,通过串口接收。

主界面:

绘制界面:

在主界面设置串口号以及波特率,点击打开串口,再点击波形显示,即可显示通过串口过来的数据波形。

主界面源码:

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;

namespace _3
{
    public delegate void ShowWindow();
    public delegate void HideWindow();
    public delegate void OpenPort();
    public delegate void ClosePort();
    public delegate Point GetMainPos();
    public delegate int GetMainWidth();

    public partial class MainForm : Form
    {
        Drawer Displayer;
        public MainForm()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;  //操控线程
        }


        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            byte[] data = new byte[serialPort1.BytesToRead];                                //定义缓冲区,因为串口事件触发时有可能收到不止一个字节
            serialPort1.Read(data, 0, data.Length);
            if (Displayer != null)
                Displayer.AddData(data);

        }

        private void CreateNewDrawer()//创建ADC绘制窗口
        {
            Displayer = new Drawer();//创建新对象

            Displayer.Show();//显示窗口
        }

        private void CreateDisplayer()
        {
            this.Left = 0;
            CreateNewDrawer();
            Rectangle Rect = Screen.GetWorkingArea(this);
           
        }

        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                serialPort1.PortName = comboBox1.Text;                                              //端口号
                serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);                             //波特率
                serialPort1.Open();                                                                 //打开串口
                button2.Enabled = false;
                button3.Enabled = true;
            }
            catch
            {
                MessageBox.Show("端口错误", "错误");
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                serialPort1.Close();     //关闭串口                                                       //关闭串口        
                button2.Enabled = true;
                button3.Enabled = false;
            }
            catch                  //一般关闭串口不会出错,故而不用编程
            {

            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            for (int i = 1; i < 6; i++)
            {
                comboBox1.Items.Add("COM" + i.ToString());                                        //添加串口
            }
            comboBox1.Text = "COM1";                                                              //默认选项
            comboBox2.Text = "4800";
           
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (Displayer == null)//第一次创建Displayer = null
            {
                CreateDisplayer();
            }
            else
            {
                if (Displayer.IsDisposed)//多次创建通过判断IsDisposed确定串口是否已关闭,避免多次创建
                {
                    CreateDisplayer();
                }
            }
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }


    }
}
 

 

绘制界面源码:

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;

namespace _3
{
    public partial class Drawer : Form
    {
        private const int Unit_length = 22;//单位格大小
        private int DrawStep = 5;//默认绘制单位
        private const int Y_Max = 255;//Y轴最大数值
        private const int MaxStep = 30;//绘制单位最大值
        private const int MinStep = 1;//绘制单位最小值 
        private const int StartPrint = 32;//点坐标偏移量
        private List<byte> DataList = new List<byte>();//数据结构----线性链表
        private List<byte> DataListZH = new List<byte>();//数据结构----线性链表
        private Pen LinesPen = new Pen(Color.FromArgb(0xaa, 0x00, 0x00));//波形颜色
        private bool KeyShift, KeyStepUp, KeyStepDown;


        public Drawer()
        {
            this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);//开启双缓冲

            this.UpdateStyles();
            InitializeComponent();
        }

        public void AddData(byte[] Data)    //将MainForm的数据推送过来
        {


            for (int i = 0; i < Data.Length; i++)
                DataList.Add(Data[i]);//链表尾部添加数据

            Invalidate();//刷新显示
        } 

        private void Drawer_Load(object sender, EventArgs e)
        {

        }


     

        private void Drawer_Paint(object sender, PaintEventArgs e)   //绘制
        {
            //String Str = "";
            e.Graphics.FillRectangle(Brushes.White, e.Graphics.ClipBounds);      //将整个窗口定义为白色
           

            if (DataList.Count - 1 >= (this.ClientRectangle.Width - StartPrint) / DrawStep)//如果数据量大于可容纳的数据量,即删除最左数据
            {
                DataList.RemoveRange(0, DataList.Count - (this.ClientRectangle.Width - StartPrint) / DrawStep - 1);
            }

            byte[] DataListt = DataList.ToArray();
            int[] D = new int[DataListt.Length];

            for (int i = 0; i < DataListt.Length; i++)
            {
                int m = DataListt[i];
                D[i] = m;
            }


            int[] D2 = new int[DataListt.Length];

            //500采样频率的50Hz陷波
            double[] B = new double[3] { 0.96897915136010271, -1.5678412012906751, 0.96897915136010271 };
            double[] A = new double[3] { 1, -1.5678412012906751, 0.93795830272020542 };
            double W1 = 0;
            double W2 = 0;
            double W3 = 0;

            for (int i = 0; i < DataListt.Length; i++)
            {
                W1 = A[0] * D[i] - A[1] * W2 - A[2] * W3;
                double s = Math.Floor(B[0] * W1 + B[1] * W2 + B[2] * W3);
                D2[i] = (int)s;
                W3 = W2;
                W2 = W1;
            }
            W1 = 0;
            W2 = 0;
            W3 = 0;

           //平滑
            int[] D3 = new int[DataListt.Length];
            D3 = D2;
            for (int i = 2; i < DataListt.Length - 3; i++)
            {
                int s =  D2[i - 2] + D2[i - 1] + D2[i] + D2[i + 1] + D2[i + 2] ;
                D3[i] = s / 5;

            }


            //数据入组
            for (int i = 0; i < D3.Length; i++)
            {
                byte[] M = BitConverter.GetBytes(D3[i]);
                DataListZH.Add(M[0]);
                Invalidate();
            }


            if (DataListZH.Count - 1 >= (this.ClientRectangle.Width - StartPrint) / DrawStep)//如果数据量大于可容纳的数据量,即删除最左数据
            {
                DataListZH.RemoveRange(0, DataListZH.Count - (this.ClientRectangle.Width - StartPrint) / DrawStep - 1);
            }

            for (int i = 0; i < DataListZH.Count - 1; i++)           //绘制波形
            {
                e.Graphics.DrawLine(LinesPen, StartPrint + i * DrawStep, 17 * Unit_length - DataListZH[i]*3 , StartPrint + (i + 1) * DrawStep, 17 * Unit_length - DataListZH[i + 1]*3 );     //绘制一条连接由坐标对指定的两个点的线条
                //(波形颜色,x1,y1,x2,y2)
            }
        }

        private void Drawer_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Shift)//shift功能键按下
                KeyShift = true;//标志位置位
            switch (e.KeyCode)//功能标志置位
            {
                case Keys.Up://放大波形
                    KeyStepUp = true;
                    break;
                case Keys.Down://缩小波形
                    KeyStepDown = true;
                    break;
                default:
                    break;
            }
        }

        private void Drawer_KeyUp(object sender, KeyEventArgs e)
        {
            if (KeyShift)
            {             

                                if (KeyStepUp)
                                {
                                    if (DrawStep < MaxStep)//绘制单位递增
                                        DrawStep++;
                                    Invalidate();
                                    KeyStepUp = false;
                                }
                                else
                                {
                                    if (KeyStepDown)
                                    {
                                        if (DrawStep > MinStep)//绘制单位递减
                                            DrawStep--;
                                        Invalidate();
                                        KeyStepDown = false;
                                    }
                                   
                                }

            }
            else//如果是其他按键,清空所有标志位
            {

                KeyStepUp = false;
                KeyStepDown = false;
            }
            KeyShift = false;//清空shift标志位
        }
    }
}
 

这是之前做实验的时候写的,现在想起来发一下,当时的的效果图没有保存。