基于C# WinForm实现的串口调试助手
一、核心代码实现(SerialDebugForm.cs)
using System;
using System.IO.Ports;
using System.Text;
using System.Timers;
using System.Windows.Forms;
namespace SerialDebugger
{
public partial class SerialDebugForm : Form
{
private SerialPort serialPort = new SerialPort();
private Timer dataTimer = new Timer(1000);
private StringBuilder recvBuffer = new StringBuilder();
private long totalRecvBytes = 0;
private long totalSendBytes = 0;
private object lockObj = new object();
public SerialDebugForm()
{
InitializeComponent();
InitializeComponents();
AutoScanPorts();
dataTimer.Elapsed += DataTimerElapsed;
}
// 初始化界面控件
private void InitializeComponents()
{
this.Size = new Size(1024, 768);
groupBox1.Text = "串口配置";
groupBox2.Text = "数据操作";
groupBox3.Text = "状态监控";
// 端口配置
comboBoxPorts.Items.AddRange(SerialPort.GetPortNames());
comboBoxBaud.Items.AddRange(new object[] { 9600, 19200, 38400, 57600, 115200 });
comboBoxData.Items.AddRange(new object[] { 8 });
comboBoxParity.Items.AddRange(Enum.GetNames(typeof(Parity)));
comboBoxStop.Items.AddRange(Enum.GetNames(typeof(StopBits)));
// 数据操作
textBoxSend.AcceptsReturn = true;
textBoxRecv.Multiline = true;
textBoxRecv.ScrollBars = ScrollBars.Both;
textBoxRecv.Font = new Font("Consolas", 12);
// 状态监控
labelStats.Text = "就绪";
dataTimer.Start();
}
// 自动扫描可用端口
private void AutoScanPorts()
{
comboBoxPorts.Items.Clear();
comboBoxPorts.Items.AddRange(SerialPort.GetPortNames());
if (comboBoxPorts.Items.Count > 0)
comboBoxPorts.SelectedIndex = 0;
}
// 打开/关闭串口
private void btnOpenClose_Click(object sender, EventArgs e)
{
try
{
if (!serialPort.IsOpen)
{
ConfigurePort();
serialPort.DataReceived += SerialPort_DataReceived;
serialPort.Open();
btnOpenClose.Text = "关闭端口";
labelStats.Text = $"已连接: {serialPort.PortName}";
}
else
{
serialPort.Close();
btnOpenClose.Text = "打开端口";
labelStats.Text = "就绪";
}
}
catch (Exception ex)
{
MessageBox.Show($"错误: {ex.Message}", "异常提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// 串口配置
private void ConfigurePort()
{
try
{
serialPort.PortName = comboBoxPorts.Text;
serialPort.BaudRate = int.Parse(comboBoxBaud.Text);
serialPort.DataBits = 8;
serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), comboBoxStop.Text);
serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), comboBoxParity.Text);
serialPort.Handshake = Handshake.None;
}
catch (Exception ex)
{
throw new InvalidOperationException($"配置错误: {ex.Message}");
}
}
// 数据接收处理
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = serialPort.ReadExisting();
lock (lockObj)
{
recvBuffer.Append($"[{DateTime.Now:HH:mm:ss.fff}] 接收: {data}\r\n");
totalRecvBytes += data.Length;
}
UpdateDisplay();
}
// HEX发送处理
private void btnSendHex_Click(object sender, EventArgs e)
{
try
{
byte[] buffer = HexStringToByteArray(textBoxSend.Text);
serialPort.Write(buffer, 0, buffer.Length);
totalSendBytes += buffer.Length;
AppendLog($"发送(HEX): {textBoxSend.Text}");
}
catch
{
MessageBox.Show("无效的HEX格式", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
// ASCII发送处理
private void btnSendText_Click(object sender, EventArgs e)
{
string text = textBoxSend.Text;
serialPort.Write(text);
totalSendBytes += text.Length;
AppendLog($"发送(ASCII): {text}");
}
// 数据展示更新
private void UpdateDisplay()
{
if (InvokeRequired)
{
Invoke(new Action(() =>
{
textBoxRecv.Text = recvBuffer.ToString();
lblRecvCount.Text = $"{totalRecvBytes} 字节";
lblSendCount.Text = $"{totalSendBytes} 字节";
labelStats.Text = $"状态: {serialPort.IsOpen ? "已连接" : "未连接"}";
}));
}
}
// HEX字符串转换
private byte[] HexStringToByteArray(string hex)
{
if (hex.Length % 2 != 0) throw new ArgumentException("无效的HEX格式");
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < hex.Length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
// 日志追加
private void AppendLog(string message)
{
lock (lockObj)
{
recvBuffer.Append($"[{DateTime.Now:HH:mm:ss.fff}] 日志: {message}\r\n");
}
}
// 定时刷新端口列表
private void DataTimerElapsed(object sender, ElapsedEventArgs e)
{
AutoScanPorts();
}
// 窗体关闭事件
private void SerialDebugForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (serialPort.IsOpen) serialPort.Close();
dataTimer.Stop();
}
}
}
二、界面设计(SerialDebugForm.Designer.cs)
partial class SerialDebugForm
{
private System.ComponentModel.IContainer components = null;
private GroupBox groupBox1;
private ComboBox comboBoxPorts;
private ComboBox comboBoxBaud;
private ComboBox comboBoxData;
private ComboBox comboBoxParity;
private ComboBox comboBoxStop;
private Button btnOpenClose;
private GroupBox groupBox2;
private TextBox textBoxSend;
private Button btnSendHex;
private Button btnSendText;
private GroupBox groupBox3;
private TextBox textBoxRecv;
private Label lblRecvCount;
private Label lblSendCount;
private Label labelStats;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.comboBoxStop = new System.Windows.Forms.ComboBox();
this.comboBoxParity = new System.Windows.Forms.ComboBox();
this.comboBoxData = new System.Windows.Forms.ComboBox();
this.comboBoxBaud = new System.Windows.Forms.ComboBox();
this.comboBoxPorts = new System.Windows.Forms.ComboBox();
this.btnOpenClose = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.btnSendHex = new System.Windows.Forms.Button();
this.btnSendText = new System.Windows.Forms.Button();
this.textBoxSend = new System.Windows.Forms.TextBox();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.textBoxRecv = new System.Windows.Forms.TextBox();
this.lblRecvCount = new System.Windows.Forms.Label();
this.lblSendCount = new System.Windows.Forms.Label();
this.labelStats = new System.Windows.Forms.Label;
// 端口配置组
this.groupBox1.Controls.Add(this.comboBoxStop);
this.groupBox1.Controls.Add(this.comboBoxParity);
this.groupBox1.Controls.Add(this.comboBoxData);
this.groupBox1.Controls.Add(this.comboBoxBaud);
this.groupBox1.Controls.Add(this.comboBoxPorts);
this.groupBox1.Controls.Add(this.btnOpenClose);
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Top;
this.groupBox1.Location = new System.Drawing.Point(0, 0);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(1024, 120);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "串口配置";
// 数据操作组
this.groupBox2.Controls.Add(this.btnSendHex);
this.groupBox2.Controls.Add(this.btnSendText);
this.groupBox2.Controls.Add(this.textBoxSend);
this.groupBox2.Dock = System.Windows.Forms.DockStyle.Fill;
this.groupBox2.Location = new System.Drawing.Point(0, 120);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(1024, 300);
this.groupBox2.TabIndex = 1;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "数据操作";
// 数据接收区
this.textBoxRecv.Dock = System.Windows.Forms.DockStyle.Fill;
this.textBoxRecv.Font = new System.Drawing.Font("Consolas", 12F);
this.textBoxRecv.Location = new System.Drawing.Point(3, 16);
this.textBoxRecv.Multiline = true;
this.textBoxRecv.Name = "textBoxRecv";
this.textBoxRecv.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.textBoxRecv.Size = new System.Drawing.Size(1018, 294);
this.textBoxRecv.TabIndex = 0;
// 状态监控组
this.groupBox3.Controls.Add(this.lblRecvCount);
this.groupBox3.Controls.Add(this.lblSendCount);
this.groupBox3.Controls.Add(this.labelStats);
this.groupBox3.Dock = System.Windows.Forms.DockStyle.Bottom;
this.groupBox3.Location = new System.Drawing.Point(0, 420);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(1024, 140);
this.groupBox3.TabIndex = 2;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "状态监控";
}
}
三、关键功能实现
1. CRC校验模块
public static class CrcCalculator
{
public static ushort CalcCRC(byte[] data)
{
ushort crc = 0xFFFF;
foreach (byte b in data)
{
crc ^= (ushort)(b << 8);
for (int i = 0; i < 8; i++)
{
if ((crc & 0x8000) != 0)
{
crc = (ushort)((crc << 1) ^ 0xA001);
}
else
{
crc <<= 1;
}
}
}
return crc;
}
}
2. 数据保存模块
public class DataManager
{
public void SaveToFile(string filePath, string data)
{
try
{
File.AppendAllText(filePath,
$"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} | {data}\r\n");
}
catch (Exception ex)
{
MessageBox.Show($"保存失败: {ex.Message}");
}
}
}
3. 流量统计模块
public class TrafficMonitor
{
private long lastRecv = 0;
private long lastSend = 0;
public (double RxRate, double TxRate) GetSpeed()
{
long currentRecv = totalRecvBytes;
long currentSend = totalSendBytes;
double rxRate = (currentRecv - lastRecv) / 1024.0; // KB/s
double txRate = (currentSend - lastSend) / 1024.0;
lastRecv = currentRecv;
lastSend = currentSend;
return (Math.Round(rxRate, 2), Math.Round(txRate, 2));
}
}
参考代码 C#串口调试助手源码 www.youwenfan.com/contentcnr/111906.html
四、部署与使用说明
1. 环境要求
- .NET Framework 4.8+
- Visual Studio 2022+
- 操作系统:Windows 10/11
2. 编译步骤
- 创建Windows Forms项目
- 添加SerialPort控件到窗体
- 将上述代码按模块划分到对应文件
- 设置启动对象为
SerialDebugForm
3. 操作指南
-
端口配置:自动扫描可用COM口,选择后设置波特率/数据位/校验位
-
数据发送:
- ASCII模式:直接输入文本点击发送
- HEX模式:输入十六进制字符串(如
01 03 00 00 00 02)
-
数据监控:
- 实时显示接收/发送数据
- 状态栏显示连接状态和统计信息
- 支持日志自动保存(默认路径:
C:\SerialLogs\debug.log)
五、扩展功能建议
- 协议解析器:添加Modbus RTU/TCP协议解析模块
- 虚拟串口:集成VSPD虚拟串口驱动支持
- 加密传输:增加AES加密模块
- 远程监控:通过TCP/IP实现远程串口访问