基于C# WinForm实现的串口调试助手

基于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. 环境要求

2. 编译步骤

  1. 创建Windows Forms项目
  2. 添加SerialPort控件到窗体
  3. 将上述代码按模块划分到对应文件
  4. 设置启动对象为SerialDebugForm

3. 操作指南

  1. 端口配置:自动扫描可用COM口,选择后设置波特率/数据位/校验位

  2. 数据发送

    • ASCII模式:直接输入文本点击发送
    • HEX模式:输入十六进制字符串(如01 03 00 00 00 02
  3. 数据监控

    • 实时显示接收/发送数据
    • 状态栏显示连接状态和统计信息
    • 支持日志自动保存(默认路径:C:\SerialLogs\debug.log

五、扩展功能建议

  1. 协议解析器:添加Modbus RTU/TCP协议解析模块
  2. 虚拟串口:集成VSPD虚拟串口驱动支持
  3. 加密传输:增加AES加密模块
  4. 远程监控:通过TCP/IP实现远程串口访问

 

专注于matlab/simulink,电子电路,编程