文章的目的为了记录使用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.效果演示
一、源码分析
- 构造函数 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(); // 启动定时器
}
- 串口初始化 InitializeSerialPort()
功能:绑定串口的数据接收和错误接收事件处理方法。
private void InitializeSerialPort()
{
// 注册数据接收事件处理程序
serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
// 注册错误接收事件处理程序
serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(SerialPort_ErrorReceived);
}
- 刷新串口列表 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;
}
}
- 打开/关闭串口按钮 buttonOpenClose_Click()
功能:切换串口的打开/关闭状态。
private void buttonOpenClose_Click(object sender, EventArgs e)
{
// 根据串口当前状态决定操作
if (serialPort.IsOpen)
{
CloseSerialPort(); // 如果已打开,则关闭
}
else
{
OpenSerialPort(); // 如果已关闭,则打开
}
}
- 打开串口 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);
}
}
- 关闭串口 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);
}
}
- 数据接收处理 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)));
}
}
- 数据显示 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();
}
- 错误接收处理 SerialPort_ErrorReceived()
功能:处理串口通信错误,在接收框中显示错误信息。
private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
{
// 在UI线程中显示错误信息
this.Invoke(new Action(() =>
textBoxReceive.AppendText($"[错误:{e.EventType}]\r\n")));
}
- 数据发送 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);
}
}
- 十六进制转换 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;
}
- 自动发送控制 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;
}
- 窗体关闭处理 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
{
/*
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
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);
}
}
}
三、效果演示
