C#串口通信与动态曲线绘制实现
一、系统概述
基于C# WinForms实现串口通信与动态曲线绘制,核心功能包括:
-
串口配置与连接:支持选择串口号、波特率等参数,连接/断开硬件设备;
-
数据接收与解析:异步接收硬件发送的串口数据(支持ASCII/二进制格式),解析为数值型数据点;
-
动态曲线绘制:使用
Chart控件实时显示数据变化趋势,支持自动滚动、缩放、数据点标记; -
异常处理:串口通信错误、数据解析失败的容错机制。
应用场景:传感器数据采集(如温度、压力)、仪器监控、工业设备数据可视化等。
二、核心组件与技术选型
| 模块 | 技术方案 | 说明 |
|---|---|---|
| 串口通信 | System.IO.Ports.SerialPort |
C#内置串口类,支持异步接收(DataReceived事件) |
| 数据解析 | 字符串分割/二进制转换(BitConverter) |
按硬件协议解析数据(如CSV格式、自定义帧) |
| 曲线绘制 | System.Windows.Forms.DataVisualization.Charting.Chart |
WinForms图表控件,支持动态更新、多曲线显示 |
| UI框架 | WinForms(.NET Framework 4.8) | 简单易用,适合快速开发桌面应用 |
三、实现步骤与代码
3.1 界面设计(WinForms)
添加以下控件(命名为MainForm):
-
串口配置区:
ComboBox(串口号)、ComboBox(波特率,预设9600/115200等)、Button(连接/断开); -
数据显示区:
TextBox(多行,显示原始数据,只读)、Chart(命名为chartData,显示动态曲线); -
状态栏:
Label(显示连接状态)。
3.2 串口通信模块(核心代码)
3.2.1 串口初始化与连接
using System.IO.Ports;
using System.Windows.Forms;
public partial class MainForm : Form
{
private SerialPort serialPort = new SerialPort();
private bool isConnected = false;
// 初始化串口参数
private void InitSerialPort()
{
// 获取可用串口号
comboBoxPort.Items.AddRange(SerialPort.GetPortNames());
if (comboBoxPort.Items.Count > 0) comboBoxPort.SelectedIndex = 0;
// 预设波特率
comboBoxBaudRate.Items.AddRange(new object[] { "9600", "19200", "38400", "57600", "115200" });
comboBoxBaudRate.SelectedIndex = 4; // 默认115200
// 串口参数配置
serialPort.DataReceived += SerialPort_DataReceived; // 异步接收事件
serialPort.ReadTimeout = 500;
serialPort.WriteTimeout = 500;
}
// 连接/断开串口
private void btnConnect_Click(object sender, EventArgs e)
{
if (!isConnected)
{
try
{
serialPort.PortName = comboBoxPort.Text;
serialPort.BaudRate = int.Parse(comboBoxBaudRate.Text);
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
serialPort.Parity = Parity.None;
serialPort.Open();
isConnected = true;
btnConnect.Text = "断开连接";
lblStatus.Text = $"已连接:{serialPort.PortName}@{serialPort.BaudRate}bps";
}
catch (Exception ex)
{
MessageBox.Show($"连接失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
serialPort.Close();
isConnected = false;
btnConnect.Text = "连接";
lblStatus.Text = "未连接";
}
}
}
3.2.2 异步接收与数据解析
假设硬件发送ASCII格式数据,每行一个浮点数(如温度值),以\n结尾:
// 串口数据接收事件(异步)
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (!serialPort.IsOpen) return;
try
{
string rawData = serialPort.ReadExisting(); // 读取所有可用数据
this.Invoke((MethodInvoker)delegate {
// 显示原始数据
txtRawData.AppendText(rawData);
// 解析数据(按行分割,过滤空行)
string[] lines = rawData.Split('\n');
foreach (string line in lines)
{
if (string.IsNullOrWhiteSpace(line)) continue;
if (float.TryParse(line.Trim(), out float value))
{
// 解析成功,添加到曲线数据
AddDataPoint(value);
}
else
{
txtRawData.AppendText($"【解析失败】{line}\r\n");
}
}
});
}
catch (Exception ex)
{
this.Invoke((MethodInvoker)delegate {
txtRawData.AppendText($"【接收错误】{ex.Message}\r\n");
});
}
}
3.3 动态曲线绘制模块(Chart控件)
3.3.1 初始化图表
using System.Windows.Forms.DataVisualization.Charting;
private Series series; // 曲线数据系列
private int maxPoints = 100; // 最大显示点数(超过则滚动)
private void InitChart()
{
// 设置图表区域
chartData.ChartAreas.Clear();
ChartArea chartArea = new ChartArea("MainArea");
chartArea.AxisX.Title = "时间(点)";
chartArea.AxisY.Title = "数值";
chartArea.AxisX.ScaleView.Zoomable = true; // 允许缩放
chartArea.CursorX.IsUserEnabled = true;
chartArea.CursorX.IsUserSelectionEnabled = true;
chartData.ChartAreas.Add(chartArea);
// 添加数据系列(折线图)
series = new Series("数据曲线");
series.ChartType = SeriesChartType.Line;
series.Color = Color.Blue;
series.BorderWidth = 2;
series.XValueType = ChartValueType.Int32;
series.YValueType = ChartValueType.Single;
chartData.Series.Add(series);
}
3.3.2 动态添加数据点
private int pointCount = 0; // 当前点数
// 添加新数据点到曲线
private void AddDataPoint(float value)
{
pointCount++;
series.Points.AddXY(pointCount, value);
// 超过最大点数时,移除最早的点(保持滚动效果)
if (series.Points.Count > maxPoints)
{
series.Points.RemoveAt(0);
}
// 自动调整X轴范围(显示最新点)
chartData.ChartAreas[0].AxisX.Minimum = Math.Max(1, pointCount - maxPoints + 1);
chartData.ChartAreas[0].AxisX.Maximum = pointCount;
// 刷新图表(避免频繁刷新可加定时器节流)
chartData.Invalidate();
}
3.4 完整主窗体代码(整合模块)
using System;
using System.IO.Ports;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace SerialPortCurveDisplay
{
public partial class MainForm : Form
{
private SerialPort serialPort = new SerialPort();
private bool isConnected = false;
private Series series;
private int maxPoints = 100;
private int pointCount = 0;
public MainForm()
{
InitializeComponent();
InitSerialPort(); // 初始化串口配置
InitChart(); // 初始化图表
}
// 【省略InitSerialPort、InitChart、btnConnect_Click、SerialPort_DataReceived、AddDataPoint方法,见上文】
#region UI控件事件
private void MainForm_Load(object sender, EventArgs e)
{
lblStatus.Text = "未连接";
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (isConnected) serialPort.Close();
}
#endregion
}
}
参考代码 C#通过串口连接硬件设备,并获取硬件数据,然后将数据点绘制成动态曲线,显示出来! www.youwenfan.com/contentcnt/182233.html
四、扩展功能
-
多曲线显示:添加多个
Series,支持同时显示多路传感器数据(如温度、湿度); -
数据存储:将解析后的数据保存到CSV文件(用
StreamWriter); -
参数配置:允许用户设置曲线颜色、线宽、最大点数等;
-
报警功能:设置阈值,数据超限时弹窗或闪烁提示。
浙公网安备 33010602011771号