从零打造 C# 工业视觉检测系统(七):串口通信 SerialPort 封装与开发
系列标签:
C#SerialPortRS232RS485串口调试HEX 收发
本文目标:掌握 C# 串口通信编程,实现带 HEX 收发功能的工业串口调试工具
一、前言
在工业自动化领域,串口通信是最经典、最可靠的设备互联方式。虽然以太网日益普及,但大量 PLC、变频器、称重仪表、继电器模块仍然只提供 RS232/RS485 接口。
本项目的剔除控制就是通过串口连接继电器模块实现的。本文将从串口基础讲起,一直到封装出一个工业级的串口调试工具。
二、串口通信基础
2.1 RS232 vs RS485
| 特性 | RS232 | RS485 |
|---|---|---|
| 传输距离 | < 15m | < 1200m |
| 连接方式 | 点对点 | 总线(一主多从) |
| 抗干扰 | 较弱 | 强 |
| 工业应用 | 近距离调试 | 产线设备联网 |
2.2 串口参数五要素
串口通信必须双方参数一致,否则收到的全是乱码:
- 波特率 (BaudRate):每秒传输的码元数,常用 9600、115200
- 数据位 (DataBits):每个字节的有效位数,通常是 8
- 校验位 (Parity):None(无)、Odd(奇)、Even(偶)
- 停止位 (StopBits):One(1)、Two(2)
- 流控制 (Handshake):None(本项目不使用)
三、C# SerialPort 核心 API
.NET 提供了 System.IO.Ports.SerialPort 类,封装了完整的串口功能。
3.1 打开与关闭
SerialPort comPort = new SerialPort();
// 配置参数
comPort.PortName = "COM3";
comPort.BaudRate = 9600;
comPort.Parity = Parity.None;
comPort.DataBits = 8;
comPort.StopBits = StopBits.One;
try
{
comPort.Open();
Console.WriteLine("串口已打开");
}
catch (Exception ex)
{
Console.WriteLine($"打开失败: {ex.Message}");
}
// 关闭
comPort.Close();
3.2 发送数据
// 发送字符串
string msg = "Hello PLC";
comPort.Write(msg);
// 发送字节数组
byte[] data = new byte[] { 0xA0, 0x01, 0x01, 0xA2 };
comPort.Write(data, 0, data.Length);
3.3 接收数据
// 查询方式读取
int bytesToRead = comPort.BytesToRead;
if (bytesToRead > 0)
{
byte[] buffer = new byte[bytesToRead];
comPort.Read(buffer, 0, bytesToRead);
string received = Encoding.UTF8.GetString(buffer);
}
四、SerialPortHelper 封装
本项目将串口功能封装为静态工具类 SerialPortHelper,便于全局调用。
4.1 枚举值定义
public enum DataBits : int
{
Five = 5, Six = 6, Sevent = 7, Eight = 8
}
public enum BaudRates : int
{
BR_9600 = 9600,
BR_19200 = 19200,
BR_38400 = 38400,
BR_57600 = 57600,
BR_115200 = 115200
}
4.2 初始化与打开
public static class SerialPortHelper
{
public static SerialPort comPort = new SerialPort();
private static string portName = "COM1";
private static BaudRates baudRate = BaudRates.BR_9600;
private static Parity parity = Parity.None;
private static StopBits stopBits = StopBits.One;
private static DataBits dataBits = DataBits.Eight;
public static void Initialize(string name, string baud,
string par, string dBits, string sBits)
{
portName = name;
baudRate = (BaudRates)Enum.Parse(typeof(BaudRates), baud);
parity = (Parity)Enum.Parse(typeof(Parity), par);
dataBits = (DataBits)Enum.Parse(typeof(DataBits), dBits);
stopBits = (StopBits)Enum.Parse(typeof(StopBits), sBits);
}
public static bool Open()
{
if (comPort.IsOpen) comPort.Close();
comPort.PortName = portName;
comPort.BaudRate = (int)baudRate;
comPort.Parity = parity;
comPort.DataBits = (int)dataBits;
comPort.StopBits = stopBits;
try
{
comPort.Open();
comPort.ReadTimeout = 1000;
comPort.WriteTimeout = 1000;
return true;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return false;
}
}
public static void Close()
{
if (comPort.IsOpen) comPort.Close();
}
}
4.3 HEX 字符串收发
工业设备常使用十六进制指令,如继电器控制:A0 01 01 A2
// HEX 字符串转字节数组
public static byte[] StringToByteArray(string hexString)
{
int length = hexString.Length / 2;
byte[] bytes = new byte[length];
for (int i = 0; i < length; ++i)
{
bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
}
return bytes;
}
// 发送 HEX 字符串(带校验)
public static void SendHexString(string hexString)
{
if (string.IsNullOrEmpty(hexString))
throw new ArgumentException("Hex string cannot be null or empty.");
if (hexString.Length % 2 != 0)
throw new ArgumentException("Hex string must have an even number of characters.");
// 验证是否为合法十六进制字符
foreach (char c in hexString)
{
if (!Uri.IsHexDigit(c))
throw new ArgumentException($"Invalid hex character: '{c}'");
}
byte[] buffer = StringToByteArray(hexString);
Write(buffer);
}
4.4 读取数据
public static bool Read(ref string result)
{
int bytesToRead = comPort.BytesToRead;
byte[] recvData = new byte[bytesToRead];
comPort.Read(recvData, 0, bytesToRead);
if (recvData.Length > 0)
{
result = Encoding.UTF8.GetString(recvData);
return true;
}
return false;
}
五、串口参数配置界面
SerialOptionForm 提供了完整的串口参数设置界面。
5.1 下拉框数据绑定
private void InitCmb()
{
// 绑定端口号
SerialPortHelper.SetPortNameValues(comboBox_Com.Items);
comboBox_Com.DropDownStyle = ComboBoxStyle.DropDownList;
// 波特率
SerialPortHelper.SetBauRateValues(comboBox_BaudRates.Items);
comboBox_BaudRates.DropDownStyle = ComboBoxStyle.DropDownList;
// 数据位
SerialPortHelper.SetDataBitsValues(comboBox_DataBits.Items);
comboBox_DataBits.DropDownStyle = ComboBoxStyle.DropDownList;
// 校验位
SerialPortHelper.SetParityValues(comboBox_Parity.Items);
comboBox_Parity.DropDownStyle = ComboBoxStyle.DropDownList;
// 停止位
SerialPortHelper.SetStopBitValues(comboBox_StopBits.Items);
comboBox_StopBits.DropDownStyle = ComboBoxStyle.DropDownList;
}
5.2 打开/关闭串口
private void button_Open_Click(object sender, EventArgs e)
{
SerialPortHelper.Initialize(comboBox_Com.Text,
comboBox_BaudRates.Text,
comboBox_Parity.Text,
comboBox_DataBits.Text,
comboBox_StopBits.Text);
if (!SerialPortHelper.Open())
{
SerialStateLight.State = UILightState.Off;
MessageBox.Show("失败", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);
}
else
{
SerialStateLight.State = UILightState.On;
MessageBox.Show("成功");
}
}
private void button_Close_Click(object sender, EventArgs e)
{
SerialPortHelper.Close();
textBox_Recive.Text = "";
SerialStateLight.State = UILightState.Off;
}
六、串口数据接收线程
为了不阻塞 UI,数据接收通常在后台线程中进行:
private Task task;
private CancellationTokenSource cts;
private void StartReadTask()
{
cts = new CancellationTokenSource();
task = new Task(() =>
{
while (true)
{
if (cts.IsCancellationRequested) break;
string result = string.Empty;
bool isGet = SerialPortHelper.Read(ref result);
if (isGet)
{
this.Invoke(new Action(() =>
{
textBox_Recive.Text = result;
}));
}
Thread.Sleep(500);
}
}, cts.Token);
task.Start();
}
private void CloseReadTask()
{
if (cts != null)
{
cts.Cancel();
task.Wait();
cts.Dispose();
}
}
七、常见问题与排查
Q1:串口打开失败?
- 检查 COM 口是否被其他程序占用
- 检查是否有权限(以管理员身份运行)
- 检查 USB 转串口驱动是否安装
Q2:发送成功但设备无响应?
- 检查波特率等参数是否与设备一致
- 确认 HEX 指令格式正确(如校验和)
- 检查接线:TX 接 RX,RX 接 TX,GND 接 GND
Q3:接收数据乱码?
- 波特率不匹配是最常见原因
- 确认编码格式(UTF-8 / ASCII / GB2312)
八、总结
本文完成了串口通信模块的讲解:
- RS232/RS485 基础与工业应用场景
- SerialPort 核心 API(打开、发送、接收、关闭)
- SerialPortHelper 静态封装类
- HEX 收发 与数据校验
- 后台接收线程 与 UI 更新
下篇预告:《从零打造 C# 工业视觉检测系统(八):Modbus RTU 协议解析与 PLC 剔除控制实战》
我们将基于串口封装,实现工业标准的 Modbus RTU 协议,完成不合格品的自动剔除控制。
欢迎点赞、收藏、关注,你的支持是我持续输出的动力!
1万+

被折叠的 条评论
为什么被折叠?



