
📖 本文目录
1什么是串口通信?
想象一下两个人打电话:一个人说,一个人听,声音一个字一个字地传过去。串口通信就是这个道理——数据按照位(bit)的顺序,一帧一帧地传输。
在工业自动化领域,几乎所有设备都支持串口通信。它的接口简单、协议成熟,是PLC、传感器、扫码枪、变频器等设备之间最常用的"沟通方式"。
核心特点:串行传输(一位一位发)、全双工(可同时收发)、距离适中、成本低、抗干扰能力因标准而异。
与USB、以太网这些"现代"接口相比,串口看起来"老",但它简单、稳定、可靠,在工业现场至今无可替代。
2串口长什么样?DB9接口详解
最经典的串口接口就是 DB9(D-sub 9针),一个梯形的9针接头。你可能在老电脑上见过它。
图:DB9 串行接口针脚定义
9个针脚各司其职,最常用的其实只有3个:
| 2 | RXD(接收) | 收数据 |
| 3 | TXD(发送) | 发数据 |
| 5 | GND(地) | 信号参考地 |
实际开发中,很多设备只接 TXD、RXD、GND 三根线就能通信,其他流控针脚可以不接。
图:DB9 公头(针)与母头(孔)
公头带针,母头带孔,对接时注意交叉连接:A的TXD接B的RXD,A的RXD接B的TXD,GND直连。
3RS232 / RS422 / RS485 三大标准
串口不是只有一种!根据电气标准不同,常见的有三种:
图:RS232 / RS422 / RS485 转换器与接线对比
| RS232 | 单端(点对点) | 约15米 | 最常见,电脑原生支持,只能1对1 |
| RS422 | 差分(全双工) | 约1200米 | 抗干扰强,距离远 |
| RS485 | 差分(半双工) | 约1200米 | 可挂多个设备(总线),工业最常用 |
记住:RS232 是"一对一打电话",RS485 是"一呼百应的对讲机"。工业现场长距离、多设备场景基本都用 RS485。
4数据帧格式:一帧数据是怎么传的
串口发数据不是"裸奔"的,每一帧都有固定的"包装格式",就像寄快递要有信封一样:
图:串口通信数据帧格式(起始位 + 数据位 + 校验位 + 停止位)
一帧数据的结构依次是:
通信双方必须约定
完全相同的帧格式,否则收到的就是乱码!这就是为什么串口调试总要先配参数。
5串口四要素:波特率、数据位、停止位、校验位
打开任何一个串口调试工具,都会看到这四个参数。它们就是通信双方的"暗号",必须一致:
| 波特率 BaudRate | 每秒传输的二进制位数(bps),决定通信速度 | 9600、19200、38400、115200 |
| 数据位 DataBits | 每帧实际数据的位数 | 6、7、8(最常用8) |
| 停止位 StopBits | 帧结束标记的位宽 | 1、1.5、2(最常用1) |
| 校验位 Parity | 错误检测方式 | 无(None)、奇校验(Odd)、偶校验(Even) |
最常用的组合:9600 波特率 + 8数据位 + 1停止位 + 无校验,简称
9600-8-N-1。新设备默认基本都是这个。
6动手前准备:虚拟串口工具
写串口程序最头疼的是——没有硬件怎么测试?
答案是用虚拟串口软件(如 Virtual Serial Port Driver),它能在电脑上创建一对"虚拟串口",比如 COM3 和 COM4,两者内部互连。你用自己的程序打开 COM3,用串口助手打开 COM4,就能互相收发数据了。
虚拟串口对是
成对出现的:发往 COM3 的数据会出现在 COM4,反之亦然。这是开发调试的神器,不需要任何真实硬件。
资料中附带了 Virtual Serial Port Driver 6.9 和 串口助手.exe,安装后创建一对虚拟串口即可开始调试。
7C# 第一步:扫描并打开串口
C# 操作串口非常简单,.NET Framework 内置了 System.IO.Ports.SerialPort 类,无需第三方库。
① 扫描电脑上的可用串口
using System.IO.Ports;
// 获取当前电脑所有可用串口名
string[] ports = SerialPort.GetPortNames();
// 绑定到下拉框
cbPort.DataSource = ports;
② 配置串口四要素
// 波特率
_serialPort.BaudRate = 9600;
// 数据位
_serialPort.DataBits = 8;
// 停止位(枚举)
_serialPort.StopBits = StopBits.One;
// 校验位(枚举)
_serialPort.Parity = Parity.None;
③ 打开 / 关闭串口
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "打开")
{
if (cbPort.SelectedIndex == -1)
{
MessageBox.Show("电脑还没有可用的串口,请先配置");
return;
}
try
{
_serialPort.PortName = cbPort.SelectedItem.ToString();
_serialPort.BaudRate = Convert.ToInt32(cbBaudRate.SelectedItem);
_serialPort.Open(); // 打开串口
button1.Text = "关闭";
}
catch (Exception ex)
{
MessageBox.Show($"串口打开失败:{ex.Message}");
}
}
else
{
_serialPort.Close(); // 关闭串口
button1.Text = "打开";
}
}
打开串口一定要用
try-catch!串口被其他程序占用、参数错误都会抛异常。
8接收数据:DataReceived 事件与跨线程UI
串口收到数据时会触发 DataReceived 事件。但有个大坑:这个事件运行在后台线程,不能直接操作UI控件,必须用 Invoke 切回UI线程。
public Form1()
{
InitializeComponent();
// 注册数据接收事件
_serialPort.DataReceived += _serialPort_DataReceived;
}
private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// 1. 根据可读字节数创建缓冲区
byte[] readData = new byte[_serialPort.BytesToRead];
// 2. 读取数据到缓冲区
_serialPort.Read(readData, 0, readData.Length);
// 3. 字节数组转字符串(UTF8编码)
string receiveMsg = Encoding.UTF8.GetString(readData);
// 4. 跨线程更新UI(必须!)
this.Invoke(new Action(() =>
{
richTextBox1.AppendText(receiveMsg + "\\r\\n");
}));
}
为什么必须 Invoke?WinForms 控件不是线程安全的,后台线程直接改控件属性会报"线程间操作无效"异常。
Invoke 把操作封送到UI线程执行。
串口接收是
异步的,数据可能分多次到达。如果需要拼包,要自己维护缓冲区和协议解析逻辑。
9发送数据:文本模式与十六进制模式
发送数据很简单,调用 Write 方法即可。但要注意:串口传输的是字节,字符串需要先编码。
文本模式发送
// 字符串 → UTF8字节数组 → 发送
byte[] writeData = Encoding.UTF8.GetBytes(chatMsg.Text);
_serialPort.Write(writeData, 0, writeData.Length);
十六进制模式发送
工业设备经常需要发十六进制指令(如 01 03 00 00 00 01),需要先把hex字符串转成字节数组:
// hex字符串 "01 03 00 01" → byte[] {0x01, 0x03, 0x00, 0x01}
private byte[] StringToHexByte(string hexString)
{
string[] buffer = hexString.Split(' ');
byte[] result = new byte[buffer.Length];
for (int i = 0; i < buffer.Length; i++)
{
result[i] = Convert.ToByte(buffer[i], 16);
}
return result;
}
// 字节数组 → hex字符串(用于显示)
private string ByteToHexString(byte[] data)
{
string result = "";
foreach (var b in data)
result += b.ToString("X2") + " ";
return result.Trim();
}
完整的发送按钮逻辑
private void btnSend_Click(object sender, EventArgs e)
{
if (!_serialPort.IsOpen)
{
MessageBox.Show("请先连接串口!");
return;
}
if (string.IsNullOrEmpty(chatMsg.Text))
{
MessageBox.Show("请输入要发送的内容");
return;
}
if (cbHexSend.Checked)
{
// 十六进制发送
byte[] data = StringToHexByte(chatMsg.Text.Trim());
_serialPort.Write(data, 0, data.Length);
}
else
{
// 文本发送
byte[] data = Encoding.UTF8.GetBytes(chatMsg.Text);
_serialPort.Write(data, 0, data.Length);
}
}
10完整实战:一个串口调试助手
把前面的知识拼起来,就是一个功能完整的串口调试助手。本项目是一个 C# WinForms 应用,包含以下功能:
- ✅ 自动扫描可用串口
- ✅ 波特率 / 数据位 / 停止位 / 校验位 可配置
- ✅ 打开 / 关闭串口
- ✅ 文本 & 十六进制 双模式收发
- ✅ 定时自动发送
- ✅ 关键词智能回复(Dictionary 匹配)
- ✅ 黑底白字 / 白底黑字 切换
关键词智能回复示例
收到"苹果"自动回复苹果的介绍,这在设备指令应答场景很实用:
Dictionary<string, string> _dic = new Dictionary<string, string>()
{
{ "苹果", "苹果原产于中亚天山山脉…" },
{ "香蕉", "香蕉富含钾和维生素…" },
{ "橘子", "橘子富含维生素C…" }
};
// 发送时匹配关键词
string input = chatMsg.Text;
if (_dic.ContainsKey(input))
{
richTextBox1.AppendText("介绍:" + _dic[input]);
}
else
{
richTextBox1.AppendText("未匹配到对应关键词\\r\\n");
}
定时自动发送
private void cbTime_CheckedChanged(object sender, EventArgs e)
{
if (cbTime.Checked)
{
timer1.Interval = Convert.ToInt32(numericUpDown1.Text);
timer1.Start();
}
else
{
timer1.Stop();
}
}
private void timer1_Tick(object sender, EventArgs e)
{
btnSend_Click(sender, e); // 定时触发发送
}
项目结构:解决方案
Day07.sln → 项目
1. 串口调试助手 → 主窗体
Form1.cs。基于 .NET Framework 4.7.2,用 Visual Studio 打开即可编译运行。
🎯 学习路线总结
| 入门 | 串口原理、DB9接口、四要素配置 |
| 进阶 | C# SerialPort 类、收发数据、跨线程UI |
| 实战 | 十六进制协议解析、Modbus RTU、多设备总线 |
串口通信看似古老,但它是工业自动化的基石。掌握了它,你就能和绝大多数工业设备"对话"了。动手写一个自己的串口调试助手,是最好的学习方式!
网硕互联帮助中心


评论前必须登录!
注册