开源 C# 快速构建(七)通讯--串口

news/2025/10/12 12:28:16/文章来源:https://www.cnblogs.com/lxjshuju/p/19136484

         文章的目的为了记录使用C# 开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

相关链接:

开源 C# 快速开发(一)基础知识

开源 C# 快速开发(二)基础控件

开源 C# 快速开发(三)复杂控件

开源 C# 快速开发(四)自定义控件--波形图

开源 C# 快速开发(五)自定义控件--仪表盘

开源 C# 快速开发(六)自定义控件--圆环

开源 C# 快速开发(七)通讯--串口

推荐链接:

开源 C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

开源 C# .net mvc 开发(六)发送邮件、定时以及CMD编程-CSDN博客

开源 C# .net mvc 开发(七)动态图片、动态表格和json数据生成-CSDN博客

开源 C# .net mvc 开发(八)IIS Express轻量化Web服务器的配置和使用-CSDN博客

开源 C# .net mvc 开发(九)websocket--服务器与客户端的实时通信-CSDN博客

本章节主要内容是:用C#编写的串口通信工具程序,基于Windows Forms和串口控件实现。

目录:

1.源码分析

2.所有源码

3.效果演示

一、源码分析

1. 构造函数 Form1()
功能:程序启动时的初始化工作,建立自动刷新串口列表的机制。

public Form1()
{
    InitializeComponent();          // 初始化窗体控件
    InitializeSerialPort();        // 初始化串口事件处理
    RefreshPortList();             // 刷新可用串口列表
    // 创建定时器,每秒刷新一次串口列表
    System.Windows.Forms.Timer timerRefreshPorts = new System.Windows.Forms.Timer();
    timerRefreshPorts.Interval = 1000;  // 设置间隔为1000毫秒
    timerRefreshPorts.Tick += (s, e) => RefreshPortList();  // Lambda表达式处理Tick事件
    timerRefreshPorts.Start();     // 启动定时器
}

2. 串口初始化 InitializeSerialPort()
功能:绑定串口的数据接收和错误接收事件处理方法。

private void InitializeSerialPort()
{
    // 注册数据接收事件处理程序
    serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
    // 注册错误接收事件处理程序
    serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(SerialPort_ErrorReceived);
}

3. 刷新串口列表 RefreshPortList()
功能:动态刷新可用串口列表,保持用户选择状态。

private void RefreshPortList()
{
    // 保存当前选择的串口
    string currentSelection = comboBoxPort.SelectedItem?.ToString();
    // 清空并重新填充串口列表
    comboBoxPort.Items.Clear();
    string[] ports = SerialPort.GetPortNames();  // 获取系统可用串口
    comboBoxPort.Items.AddRange(ports);          // 添加到下拉框
    // 恢复之前的选择(如果仍然存在)
    if (!string.IsNullOrEmpty(currentSelection) && comboBoxPort.Items.Contains(currentSelection))
    {
        comboBoxPort.SelectedItem = currentSelection;
    }
    // 否则选择第一个可用串口
    else if (comboBoxPort.Items.Count > 0)
    {
        comboBoxPort.SelectedIndex = 0;
    }
}

4. 打开/关闭串口按钮 buttonOpenClose_Click()

功能:切换串口的打开/关闭状态。

private void buttonOpenClose_Click(object sender, EventArgs e)
{
    // 根据串口当前状态决定操作
    if (serialPort.IsOpen)
    {
        CloseSerialPort();    // 如果已打开,则关闭
    }
    else
    {
        OpenSerialPort();     // 如果已关闭,则打开
    }
}


5. 打开串口 OpenSerialPort()
功能:根据用户选择的参数配置并打开串口。

private void OpenSerialPort()
{
    // 检查是否选择了串口
    if (comboBoxPort.SelectedItem == null)
    {
        MessageBox.Show("请选择串口!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }
    try
    {
        // 配置串口参数
        serialPort.PortName = comboBoxPort.SelectedItem.ToString();
        serialPort.BaudRate = int.Parse(comboBoxBaudRate.SelectedItem.ToString());
        serialPort.DataBits = int.Parse(comboBoxDataBits.SelectedItem.ToString());
        // 配置校验位(5种模式)
        switch (comboBoxParity.SelectedItem.ToString())
        {
            case "None": serialPort.Parity = Parity.None; break;
            case "Odd": serialPort.Parity = Parity.Odd; break;
            case "Even": serialPort.Parity = Parity.Even; break;
            case "Mark": serialPort.Parity = Parity.Mark; break;
            case "Space": serialPort.Parity = Parity.Space; break;
        }
        // 配置停止位(3种模式)
        switch (comboBoxStopBits.SelectedItem.ToString())
        {
            case "1": serialPort.StopBits = StopBits.One; break;
            case "1.5": serialPort.StopBits = StopBits.OnePointFive; break;
            case "2": serialPort.StopBits = StopBits.Two; break;
        }
        serialPort.Open();  // 打开串口
        // 更新UI状态
        buttonOpenClose.Text = "关闭串口";
        comboBoxPort.Enabled = false;
        comboBoxBaudRate.Enabled = false;
        comboBoxDataBits.Enabled = false;
        comboBoxParity.Enabled = false;
        comboBoxStopBits.Enabled = false;
    }
    catch (Exception ex)
    {
        MessageBox.Show($"打开串口失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}


6. 关闭串口 CloseSerialPort()
功能:安全关闭串口并恢复界面控件的可用状态。

private void CloseSerialPort()
{
    try
    {
        // 安全关闭串口
        if (serialPort.IsOpen)
        {
            serialPort.Close();
        }
        // 恢复UI状态
        buttonOpenClose.Text = "打开串口";
        comboBoxPort.Enabled = true;
        comboBoxBaudRate.Enabled = true;
        comboBoxDataBits.Enabled = true;
        comboBoxParity.Enabled = true;
        comboBoxStopBits.Enabled = true;
        // 停止自动发送功能
        checkBoxAutoSend.Checked = false;
    }
    catch (Exception ex)
    {
        MessageBox.Show($"关闭串口失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}


7. 数据接收处理 SerialPort_DataReceived()
功能:在后台线程中接收串口数据,通过线程安全的方式更新UI。

private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        // 读取可用数据
        int bytesToRead = serialPort.BytesToRead;
        byte[] buffer = new byte[bytesToRead];
        serialPort.Read(buffer, 0, bytesToRead);
        // 通过Invoke在UI线程中更新显示
        this.Invoke(new Action(() => DisplayReceivedData(buffer)));
    }
    catch (Exception ex)
    {
        // 错误信息也要在UI线程中显示
        this.Invoke(new Action(() =>
            MessageBox.Show($"接收数据错误:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)));
    }
}


8. 数据显示 DisplayReceivedData()
功能:将接收到的字节数据按指定格式显示在文本框中。

private void DisplayReceivedData(byte[] data)
{
    // 根据复选框选择显示格式
    if (checkBoxHexReceive.Checked)
    {
        // 十六进制显示:将字节数组转换为"XX XX XX"格式
        string hexString = BitConverter.ToString(data).Replace("-", " ");
        textBoxReceive.AppendText(hexString + " ");
    }
    else
    {
        // ASCII显示:将字节数组转换为字符串
        string asciiString = Encoding.ASCII.GetString(data);
        textBoxReceive.AppendText(asciiString);
    }
    // 自动滚动到最新内容
    textBoxReceive.SelectionStart = textBoxReceive.Text.Length;
    textBoxReceive.ScrollToCaret();
}

9. 错误接收处理 SerialPort_ErrorReceived()
功能:处理串口通信错误,在接收框中显示错误信息。

private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
    // 在UI线程中显示错误信息
    this.Invoke(new Action(() =>
        textBoxReceive.AppendText($"[错误:{e.EventType}]\r\n")));
}


10. 数据发送 SendData()
功能:处理数据发送逻辑,支持两种格式。

private void SendData()
{
    // 前置检查
    if (!serialPort.IsOpen)
    {
        MessageBox.Show("请先打开串口!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
    }
    if (string.IsNullOrEmpty(textBoxSend.Text))
    {
        MessageBox.Show("发送内容不能为空!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
    }
    try
    {
        byte[] sendData;
        // 根据复选框选择发送格式
        if (checkBoxHexSend.Checked)
        {
            // 十六进制发送
            sendData = HexStringToByteArray(textBoxSend.Text);
        }
        else
        {
            // ASCII发送
            sendData = Encoding.ASCII.GetBytes(textBoxSend.Text);
        }
        serialPort.Write(sendData, 0, sendData.Length);  // 发送数据
    }
    catch (Exception ex)
    {
        MessageBox.Show($"发送数据失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}


11. 十六进制转换 HexStringToByteArray()
功能:将十六进制字符串转换为字节数组,支持灵活的输入格式。

private byte[] HexStringToByteArray(string hex)
{
    // 清理字符串:移除所有空格、横线、换行符等
    hex = hex.Replace(" ", "").Replace("-", "").Replace("\r", "").Replace("\n", "").Replace("\t", "");
    // 验证长度
    if (hex.Length % 2 != 0)
    {
        throw new ArgumentException("十六进制字符串长度必须为偶数");
    }
    // 每两个字符转换成一个字节
    byte[] bytes = new byte[hex.Length / 2];
    for (int i = 0; i < hex.Length; i += 2)
    {
        string hexByte = hex.Substring(i, 2);           // 提取两个字符
        bytes[i / 2] = Convert.ToByte(hexByte, 16);    // 转换为字节
    }
    return bytes;
}


12. 自动发送控制 checkBoxAutoSend_CheckedChanged()
功能:管理自动发送功能的启动和停止。

private void checkBoxAutoSend_CheckedChanged(object sender, EventArgs e)
{
    if (checkBoxAutoSend.Checked)
    {
        // 启用自动发送前的检查
        if (!serialPort.IsOpen)        {
            MessageBox.Show("请先打开串口!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            checkBoxAutoSend.Checked = false;
            return;
        }
        // 配置并启动定时器
        timerAutoSend.Interval = (int)numericUpDownInterval.Value;
        timerAutoSend.Tick += (s, args) => SendData();  // 每次Tick事件触发发送
        timerAutoSend.Start();
    }
    else
    {
        // 停止自动发送
        timerAutoSend.Stop();
    }
    // 控制间隔设置控件的可用状态
    numericUpDownInterval.Enabled = !checkBoxAutoSend.Checked;
}

13. 窗体关闭处理 OnFormClosing()
功能:重写窗体关闭事件,确保资源正确释放。

protected override void OnFormClosing(FormClosingEventArgs e)
{
    // 确保程序退出前关闭串口
    if (serialPort.IsOpen)
    {
        serialPort.Close();
    }
    base.OnFormClosing(e);  // 调用基类方法
}

二、所有源码

Form1.designer.cs文件

using System;
using System.Drawing;
using System.IO.Ports;
using System.Windows.Forms;
namespace _7_uart
{partial class Form1{/*/// /// 必需的设计器变量。/// private System.ComponentModel.IContainer components = null;/// /// 清理所有正在使用的资源。/// /// 如果应释放托管资源,为 true;否则为 false。protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows 窗体设计器生成的代码/// /// 设计器支持所需的方法 - 不要修改/// 使用代码编辑器修改此方法的内容。/// private void InitializeComponent(){this.components = new System.ComponentModel.Container();this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(800, 450);this.Text = "Form1";}#endregion*/private System.ComponentModel.IContainer components = null;private ComboBox comboBoxPort;private ComboBox comboBoxBaudRate;private ComboBox comboBoxDataBits;private ComboBox comboBoxParity;private ComboBox comboBoxStopBits;private Button buttonOpenClose;private TextBox textBoxSend;private TextBox textBoxReceive;private Button buttonSend;private CheckBox checkBoxHexSend;private CheckBox checkBoxHexReceive;private CheckBox checkBoxAutoSend;private NumericUpDown numericUpDownInterval;private Label label1, label2, label3, label4, label5, label6, label7;private SerialPort serialPort;private System.Windows.Forms.Timer timerAutoSend;protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();if (serialPort != null && serialPort.IsOpen)serialPort.Close();}base.Dispose(disposing);}private void InitializeComponent(){this.components = new System.ComponentModel.Container();this.comboBoxPort = new System.Windows.Forms.ComboBox();this.comboBoxBaudRate = new System.Windows.Forms.ComboBox();this.comboBoxDataBits = new System.Windows.Forms.ComboBox();this.comboBoxParity = new System.Windows.Forms.ComboBox();this.comboBoxStopBits = new System.Windows.Forms.ComboBox();this.buttonOpenClose = new System.Windows.Forms.Button();this.textBoxSend = new System.Windows.Forms.TextBox();this.textBoxReceive = new System.Windows.Forms.TextBox();this.buttonSend = new System.Windows.Forms.Button();this.checkBoxHexSend = new System.Windows.Forms.CheckBox();this.checkBoxHexReceive = new System.Windows.Forms.CheckBox();this.checkBoxAutoSend = new System.Windows.Forms.CheckBox();this.numericUpDownInterval = new System.Windows.Forms.NumericUpDown();this.label1 = new System.Windows.Forms.Label();this.label2 = new System.Windows.Forms.Label();this.label3 = new System.Windows.Forms.Label();this.label4 = new System.Windows.Forms.Label();this.label5 = new System.Windows.Forms.Label();this.label6 = new System.Windows.Forms.Label();this.label7 = new System.Windows.Forms.Label();this.serialPort = new System.IO.Ports.SerialPort(this.components);this.timerAutoSend = new System.Windows.Forms.Timer(this.components);((System.ComponentModel.ISupportInitialize)(this.numericUpDownInterval)).BeginInit();this.SuspendLayout();//// comboBoxPort//this.comboBoxPort.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;this.comboBoxPort.Location = new System.Drawing.Point(80, 20);this.comboBoxPort.Name = "comboBoxPort";this.comboBoxPort.Size = new System.Drawing.Size(100, 23);this.comboBoxPort.TabIndex = 0;//// comboBoxBaudRate//this.comboBoxBaudRate.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;this.comboBoxBaudRate.Items.AddRange(new object[] {"9600","19200","38400","57600","115200"});this.comboBoxBaudRate.Location = new System.Drawing.Point(80, 60);this.comboBoxBaudRate.Name = "comboBoxBaudRate";this.comboBoxBaudRate.Size = new System.Drawing.Size(100, 23);this.comboBoxBaudRate.TabIndex = 1;//// comboBoxDataBits//this.comboBoxDataBits.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;this.comboBoxDataBits.Items.AddRange(new object[] {"5","6","7","8"});this.comboBoxDataBits.Location = new System.Drawing.Point(280, 20);this.comboBoxDataBits.Name = "comboBoxDataBits";this.comboBoxDataBits.Size = new System.Drawing.Size(100, 23);this.comboBoxDataBits.TabIndex = 2;//// comboBoxParity//this.comboBoxParity.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;this.comboBoxParity.Items.AddRange(new object[] {"None","Odd","Even","Mark","Space"});this.comboBoxParity.Location = new System.Drawing.Point(280, 60);this.comboBoxParity.Name = "comboBoxParity";this.comboBoxParity.Size = new System.Drawing.Size(100, 23);this.comboBoxParity.TabIndex = 3;//// comboBoxStopBits//this.comboBoxStopBits.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;this.comboBoxStopBits.Items.AddRange(new object[] {"1","1.5","2"});this.comboBoxStopBits.Location = new System.Drawing.Point(480, 20);this.comboBoxStopBits.Name = "comboBoxStopBits";this.comboBoxStopBits.Size = new System.Drawing.Size(100, 23);this.comboBoxStopBits.TabIndex = 4;//// buttonOpenClose//this.buttonOpenClose.Location = new System.Drawing.Point(480, 60);this.buttonOpenClose.Name = "buttonOpenClose";this.buttonOpenClose.Size = new System.Drawing.Size(100, 30);this.buttonOpenClose.TabIndex = 5;this.buttonOpenClose.Text = "打开串口";this.buttonOpenClose.Click += new System.EventHandler(this.buttonOpenClose_Click);//// textBoxSend//this.textBoxSend.Location = new System.Drawing.Point(20, 150);this.textBoxSend.Multiline = true;this.textBoxSend.Name = "textBoxSend";this.textBoxSend.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;this.textBoxSend.Size = new System.Drawing.Size(560, 100);this.textBoxSend.TabIndex = 6;//// textBoxReceive//this.textBoxReceive.Location = new System.Drawing.Point(20, 313);this.textBoxReceive.Multiline = true;this.textBoxReceive.Name = "textBoxReceive";this.textBoxReceive.ReadOnly = true;this.textBoxReceive.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;this.textBoxReceive.Size = new System.Drawing.Size(560, 187);this.textBoxReceive.TabIndex = 7;//// buttonSend//this.buttonSend.Location = new System.Drawing.Point(480, 260);this.buttonSend.Name = "buttonSend";this.buttonSend.Size = new System.Drawing.Size(100, 30);this.buttonSend.TabIndex = 8;this.buttonSend.Text = "发送";this.buttonSend.Click += new System.EventHandler(this.buttonSend_Click);//// checkBoxHexSend//this.checkBoxHexSend.Location = new System.Drawing.Point(20, 260);this.checkBoxHexSend.Name = "checkBoxHexSend";this.checkBoxHexSend.Size = new System.Drawing.Size(100, 20);this.checkBoxHexSend.TabIndex = 9;this.checkBoxHexSend.Text = "十六进制发送";//// checkBoxHexReceive//this.checkBoxHexReceive.Location = new System.Drawing.Point(120, 260);this.checkBoxHexReceive.Name = "checkBoxHexReceive";this.checkBoxHexReceive.Size = new System.Drawing.Size(100, 20);this.checkBoxHexReceive.TabIndex = 10;this.checkBoxHexReceive.Text = "十六进制接收";//// checkBoxAutoSend//this.checkBoxAutoSend.Location = new System.Drawing.Point(220, 260);this.checkBoxAutoSend.Name = "checkBoxAutoSend";this.checkBoxAutoSend.Size = new System.Drawing.Size(80, 20);this.checkBoxAutoSend.TabIndex = 11;this.checkBoxAutoSend.Text = "自动发送";this.checkBoxAutoSend.CheckedChanged += new System.EventHandler(this.checkBoxAutoSend_CheckedChanged);//// numericUpDownInterval//this.numericUpDownInterval.Location = new System.Drawing.Point(310, 260);this.numericUpDownInterval.Maximum = new decimal(new int[] {10000,0,0,0});this.numericUpDownInterval.Minimum = new decimal(new int[] {100,0,0,0});this.numericUpDownInterval.Name = "numericUpDownInterval";this.numericUpDownInterval.Size = new System.Drawing.Size(60, 25);this.numericUpDownInterval.TabIndex = 12;this.numericUpDownInterval.Value = new decimal(new int[] {1000,0,0,0});//// label1//this.label1.Location = new System.Drawing.Point(20, 20);this.label1.Name = "label1";this.label1.Size = new System.Drawing.Size(50, 20);this.label1.TabIndex = 13;this.label1.Text = "串口:";//// label2//this.label2.Location = new System.Drawing.Point(20, 60);this.label2.Name = "label2";this.label2.Size = new System.Drawing.Size(50, 20);this.label2.TabIndex = 14;this.label2.Text = "波特率:";//// label3//this.label3.Location = new System.Drawing.Point(220, 20);this.label3.Name = "label3";this.label3.Size = new System.Drawing.Size(50, 20);this.label3.TabIndex = 15;this.label3.Text = "数据位:";//// label4//this.label4.Location = new System.Drawing.Point(220, 60);this.label4.Name = "label4";this.label4.Size = new System.Drawing.Size(50, 20);this.label4.TabIndex = 16;this.label4.Text = "校验位:";//// label5//this.label5.Location = new System.Drawing.Point(420, 20);this.label5.Name = "label5";this.label5.Size = new System.Drawing.Size(50, 20);this.label5.TabIndex = 17;this.label5.Text = "停止位:";//// label6//this.label6.Location = new System.Drawing.Point(20, 120);this.label6.Name = "label6";this.label6.Size = new System.Drawing.Size(50, 20);this.label6.TabIndex = 18;this.label6.Text = "发送:";//// label7//this.label7.Location = new System.Drawing.Point(20, 288);this.label7.Name = "label7";this.label7.Size = new System.Drawing.Size(50, 20);this.label7.TabIndex = 19;this.label7.Text = "接收:";//// Form1//this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(600, 520);this.Controls.Add(this.comboBoxPort);this.Controls.Add(this.comboBoxBaudRate);this.Controls.Add(this.comboBoxDataBits);this.Controls.Add(this.comboBoxParity);this.Controls.Add(this.comboBoxStopBits);this.Controls.Add(this.buttonOpenClose);this.Controls.Add(this.textBoxSend);this.Controls.Add(this.textBoxReceive);this.Controls.Add(this.buttonSend);this.Controls.Add(this.checkBoxHexSend);this.Controls.Add(this.checkBoxHexReceive);this.Controls.Add(this.checkBoxAutoSend);this.Controls.Add(this.numericUpDownInterval);this.Controls.Add(this.label1);this.Controls.Add(this.label2);this.Controls.Add(this.label3);this.Controls.Add(this.label4);this.Controls.Add(this.label5);this.Controls.Add(this.label6);this.Controls.Add(this.label7);this.Name = "Form1";this.Text = "串口调试工具";((System.ComponentModel.ISupportInitialize)(this.numericUpDownInterval)).EndInit();this.ResumeLayout(false);this.PerformLayout();}}
}

From1.cs文件

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;
using System;
using System.IO.Ports;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace _7_uart
{public partial class Form1 : Form{/*public Form1(){InitializeComponent();}*/public Form1(){InitializeComponent();InitializeSerialPort();RefreshPortList();// 定时刷新可用串口System.Windows.Forms.Timer timerRefreshPorts = new System.Windows.Forms.Timer();timerRefreshPorts.Interval = 1000;timerRefreshPorts.Tick += (s, e) => RefreshPortList();timerRefreshPorts.Start();}private void InitializeSerialPort(){serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(SerialPort_ErrorReceived);}private void RefreshPortList(){string currentSelection = comboBoxPort.SelectedItem?.ToString();comboBoxPort.Items.Clear();string[] ports = SerialPort.GetPortNames();comboBoxPort.Items.AddRange(ports);if (!string.IsNullOrEmpty(currentSelection) && comboBoxPort.Items.Contains(currentSelection)){comboBoxPort.SelectedItem = currentSelection;}else if (comboBoxPort.Items.Count > 0){comboBoxPort.SelectedIndex = 0;}}private void buttonOpenClose_Click(object sender, EventArgs e){if (serialPort.IsOpen){CloseSerialPort();}else{OpenSerialPort();}}private void OpenSerialPort(){if (comboBoxPort.SelectedItem == null){MessageBox.Show("请选择串口!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);return;}try{serialPort.PortName = comboBoxPort.SelectedItem.ToString();serialPort.BaudRate = int.Parse(comboBoxBaudRate.SelectedItem.ToString());serialPort.DataBits = int.Parse(comboBoxDataBits.SelectedItem.ToString());// 设置校验位switch (comboBoxParity.SelectedItem.ToString()){case "None": serialPort.Parity = Parity.None; break;case "Odd": serialPort.Parity = Parity.Odd; break;case "Even": serialPort.Parity = Parity.Even; break;case "Mark": serialPort.Parity = Parity.Mark; break;case "Space": serialPort.Parity = Parity.Space; break;}// 设置停止位switch (comboBoxStopBits.SelectedItem.ToString()){case "1": serialPort.StopBits = StopBits.One; break;case "1.5": serialPort.StopBits = StopBits.OnePointFive; break;case "2": serialPort.StopBits = StopBits.Two; break;}serialPort.Open();buttonOpenClose.Text = "关闭串口";comboBoxPort.Enabled = false;comboBoxBaudRate.Enabled = false;comboBoxDataBits.Enabled = false;comboBoxParity.Enabled = false;comboBoxStopBits.Enabled = false;}catch (Exception ex){MessageBox.Show($"打开串口失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);}}private void CloseSerialPort(){try{if (serialPort.IsOpen){serialPort.Close();}buttonOpenClose.Text = "打开串口";comboBoxPort.Enabled = true;comboBoxBaudRate.Enabled = true;comboBoxDataBits.Enabled = true;comboBoxParity.Enabled = true;comboBoxStopBits.Enabled = true;// 停止自动发送checkBoxAutoSend.Checked = false;}catch (Exception ex){MessageBox.Show($"关闭串口失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);}}private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e){try{int bytesToRead = serialPort.BytesToRead;byte[] buffer = new byte[bytesToRead];serialPort.Read(buffer, 0, bytesToRead);// 在UI线程中更新接收文本框this.Invoke(new Action(() => DisplayReceivedData(buffer)));}catch (Exception ex){this.Invoke(new Action(() =>MessageBox.Show($"接收数据错误:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error)));}}private void DisplayReceivedData(byte[] data){if (checkBoxHexReceive.Checked){// 十六进制显示string hexString = BitConverter.ToString(data).Replace("-", " ");textBoxReceive.AppendText(hexString + " ");}else{// ASCII显示string asciiString = Encoding.ASCII.GetString(data);textBoxReceive.AppendText(asciiString);}// 自动滚动到最新内容textBoxReceive.SelectionStart = textBoxReceive.Text.Length;textBoxReceive.ScrollToCaret();}private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e){this.Invoke(new Action(() =>textBoxReceive.AppendText($"[错误:{e.EventType}]\r\n")));}private void buttonSend_Click(object sender, EventArgs e){SendData();}private void SendData(){if (!serialPort.IsOpen){MessageBox.Show("请先打开串口!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);return;}if (string.IsNullOrEmpty(textBoxSend.Text)){MessageBox.Show("发送内容不能为空!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);return;}try{byte[] sendData;if (checkBoxHexSend.Checked){// 十六进制发送sendData = HexStringToByteArray(textBoxSend.Text);}else{// ASCII发送sendData = Encoding.ASCII.GetBytes(textBoxSend.Text);}serialPort.Write(sendData, 0, sendData.Length);}catch (Exception ex){MessageBox.Show($"发送数据失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);}}private byte[] HexStringToByteArray(string hex){hex = hex.Replace(" ", "").Replace("-", "").Replace("\r", "").Replace("\n", "").Replace("\t", "");if (hex.Length % 2 != 0){throw new ArgumentException("十六进制字符串长度必须为偶数");}byte[] bytes = new byte[hex.Length / 2];for (int i = 0; i < hex.Length; i += 2){string hexByte = hex.Substring(i, 2);bytes[i / 2] = Convert.ToByte(hexByte, 16);}return bytes;}private void checkBoxAutoSend_CheckedChanged(object sender, EventArgs e){if (checkBoxAutoSend.Checked){if (!serialPort.IsOpen){MessageBox.Show("请先打开串口!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);checkBoxAutoSend.Checked = false;return;}timerAutoSend.Interval = (int)numericUpDownInterval.Value;timerAutoSend.Tick += (s, args) => SendData();timerAutoSend.Start();}else{timerAutoSend.Stop();}numericUpDownInterval.Enabled = !checkBoxAutoSend.Checked;}protected override void OnFormClosing(FormClosingEventArgs e){if (serialPort.IsOpen){serialPort.Close();}base.OnFormClosing(e);}}
}

三、效果演示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/935353.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025新能源冲压件厂家权威推荐榜:技术革新与品质保障深度解

2025新能源冲压件厂家权威推荐榜:技术革新与品质保障深度解新能源汽车产业的蓬勃发展带动了上游零部件领域的全面升级,其中冲压件作为电池包结构、电机壳体等关键部件的核心组成部分,其技术标准与品质要求正经历着革…

浮点数的相等性判断

在编程中,浮点数(如 C/C++ 中的float、double,Python 中的float)的赋值和相等性判断需要特别注意。因为浮点数在计算机中是近似表示的,直接使用==判断相等可能导致逻辑错误。一、浮点数的相等性判断 禁止直接使用…

ubuntu18

deb http://security.debian.org/debian-security buster/updates main 第三步:apt-get update之后若出现下面提示: 由于没有公钥,无法验证下列签名: NO_PUBKEY 112695A0E562B32A NO_PUBKEY 54404762BBB6E853 sudo…

2025国庆dp

经典例题 摆渡车 设fi表示i这个时刻发车最小答案,枚举上一次发车的时间j,容易转移 但这是O(t^2) 考虑优化 1.斜率优化 2.发现n,m<t,设计fi这种状态很浪费 优化1:若两次发车间隔>2m,完全可以再发一辆车,于是…

2025数控锯床厂家权威推荐榜:精密加工与高效生产口碑之选

2025数控锯床厂家权威推荐榜:精密加工与高效生产口碑之选在制造业转型升级的浪潮中,数控锯床作为金属加工领域的关键设备,其技术水平与性能表现直接影响着生产效率和产品质量。随着工业4.0时代的深入发展,数控锯床…

Java集成SaToken构建登录

Java集成SaToken构建登录pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &q…

FFmpeg开发笔记(八十二)使用国产直播服务器smart_rtmpd执行推流操作

​《FFmpeg开发实战:从零基础到短视频上线》一书的“10.2.2 FFmpeg向网络推流”介绍了轻量级流媒体服务器MediaMTX,通过该工具可以测试RTSP/RTMP等流媒体协议的推拉流。不过MediaMTX的功能比较简单,也不方便个性化…

实验室装修厂家最新权威推荐榜:专业设计与施工品质深度解析

实验室装修厂家最新权威推荐榜:专业设计与施工品质深度解析在科技创新驱动发展的时代背景下,实验室作为科研创新的重要载体,其装修质量直接关系到实验结果的准确性和科研人员的安全。优秀的实验室装修不仅要满足基本…

生成式AI在红队测试中的应用:构建自动化工具

本文探讨如何利用生成式AI和大语言模型构建红队测试工具,包括自动化社交工程、代码生成和侦察等关键技术,通过实际Python代码示例展示AI在网络安全领域的实际应用。生成式AI为黑客服务:构建红队测试工具 红队测试人…

杂题 10月份

P3509 [POI 2010] ZAB-Frog 先考虑双指针处理出 \(nxt\),然后就是倍增板子了。注意直接倍增会被卡常,有一个 trick 是要二进制分解然后就没了。 P3811 【模板】模意义下的乘法逆元 卧槽,本以为是简单的费马小定理求…

2025年UV LED点光源厂家权威推荐榜:精准固化与高效能

2025年UV LED点光源厂家权威推荐榜:精准固化与高效能随着工业4.0时代的深入发展,UV LED点光源作为精密制造领域的关键设备,正迎来技术革新与市场需求的爆发式增长。据行业数据显示,全球UV固化设备市场规模预计在20…

NVR软件快速对比表

NVR软件快速对比表 一、核心数据对比(百分制评分)软件名称 系统占用 功能丰富度 AI智能 易用性 中文支持 性价比 总评分 推荐度Agent DVR 75 98 95 92 80 98 95 ⭐⭐⭐⭐⭐Surveillance Station 70 95 85 95 100 60 …

20232410 2025-2026-1 《网络与系统攻防技术》 实验一实验报告

一、实验目的 本次实践的对象是一个名为pwn1的linux可执行文件。 该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串。 该程序同时包含另一个代码片段,getShell,会返回一个可用Shell。正…

在Windows系统打造基于ConEmu的命令行工具环境

需求背景 对于git工具的使用,个人习惯了通过命令行进行操作。特别是当需要管理多个项目时,希望命令行工具支持多标签页方式便于切换,并且具备保存历史标签页的功能。 上述诉求在Linux/Mac系统下都比较好实现,但是在…

2025工矿灯厂家最新权威推荐榜:工业照明技术革新与品质保障

2025工矿灯厂家最新权威推荐榜:工业照明技术革新与品质保障在工业4.0和智能制造快速推进的背景下,工矿照明领域正经历着深刻的技术变革。现代工矿灯不仅需要满足基础照明需求,更要兼顾能效管理、智能控制和环境适应…

ZR 2025 十一集训 Day 1

数据结构内容 请输入内容

2025广东粉末厂家最新权威推荐榜:技术实力与市场口碑深度解

2025广东粉末厂家最新权威推荐榜:技术实力与市场口碑深度解析在制造业转型升级的浪潮中,广东作为中国制造业的重要基地,粉末材料行业迎来了前所未有的发展机遇。粉末材料作为现代制造业的基础原料,其质量直接关系到…

[KaibaMath]1007 关于数列极限存在的唯一性证明

[KaibaMath]1007 关于数列极限存在的唯一性证明基于∀ε>0,常数λ>0,|a-b|<λε => a=b和绝对值的三角形不等式|a-b|<=|a|+|b|,我们可证明数列极限存在的唯一性定理。|a-b|<λε => a=b的证明…

20232418 2025-2026-1 《网络与系统攻防技术》实验一实验报告

一、实验目的1掌握NOP, JNE, JE, JMP, CMP汇编指令的机器码。2掌握反汇编与十六进制编程器。3能正确修改机器指令改变程序执行流程。4能正确构造payload进行bof攻击。 二、实验环境 VMware Workstation pro环境下安装k…

十月模拟赛

十月模拟赛10.3 T3 序列修改 在时间轴上考虑,相当于每个时间除了自己该有的还能额外带上 \(k - 1\) 个东西。则对于每个数,将每两个相邻的出现中间视为一条线段,则希望选出一些线段满足每个位置被覆盖不超过 \(k - …