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

实现单片机与电脑通讯,通过串口接收。
主界面:c|C#实现串口通讯实时显示波形并实现平滑滤波和50Hz滤波
文章图片

绘制界面:c|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 = https://www.it610.com/article/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 DataList = new List(); //数据结构----线性链表
private List DataListZH = new List(); //数据结构----线性链表
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标志位
}
}
}

【c|C#实现串口通讯实时显示波形并实现平滑滤波和50Hz滤波】这是之前做实验的时候写的,现在想起来发一下,当时的的效果图没有保存。

    推荐阅读