news 2026/4/17 6:25:24

一文说清UART串口通信中奇偶校验的作用与配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一文说清UART串口通信中奇偶校验的作用与配置

深入理解UART通信中的奇偶校验:不只是加一位那么简单

你有没有遇到过这样的情况?系统在实验室跑得好好的,一搬到现场就频繁“抽风”——串口接收的数据莫名其妙变成乱码,设备偶尔死机重启,但复现又极其困难。排查了半天电源、时钟、信号完整性,最后发现罪魁祸首竟然是一个没配置的校验位

这正是我们今天要聊的话题:UART串口通信中那个看似不起眼,却能在关键时刻救你一命的奇偶校验(Parity Check)机制


为什么异步通信特别需要“自我检查”?

UART作为嵌入式系统中最古老的通信方式之一,至今仍在传感器、工业控制、调试接口等领域广泛使用。它的优势很明显:两根线(TX/RX),无需共享时钟,硬件简单到一颗MCU就能搞定。

但也正因为是异步通信——发送和接收端靠各自的时钟驱动,没有同步信号对齐——这就埋下了隐患。一旦双方波特率有微小偏差,或者传输过程中受到电磁干扰(EMI)、地电平漂移、线路阻抗不匹配等问题,某个比特就可能被错误采样。

比如原本该是0的电平被噪声拉高成了1,或者边沿抖动导致采样点偏移……这种“单比特翻转”虽然听起来概率低,但在电机启停、开关电源附近、长线缆传输等场景下,其实相当常见。

这时候,如果没有任何差错检测机制,错误数据就会被当作正常指令处理。轻则参数异常,重则触发误动作,甚至引发安全事故。

所以问题来了:怎么让接收方知道“我收到的这个字节可能是错的”?

答案就是——引入冗余信息来验证数据的一致性。而最轻量级的方式,就是奇偶校验


奇偶校验的本质:用1 bit换来一次“健康自检”

我们可以把奇偶校验看作是一种“数据体检”。它不治病(不能纠错),但能告诉你“你可能生病了”。

具体怎么做?

在每个UART数据帧中,除了起始位、数据位、停止位之外,还可以插入一个额外的校验位(Parity Bit),它的值由前面的数据位决定:

  • 偶校验(Even Parity):确保整个数据单元(含校验位)中“1”的个数为偶数。
  • 奇校验(Odd Parity):确保“1”的个数为奇数。

举个例子:

假设你要发送的数据是1010_1100,其中共有4个“1”。

校验模式目标奇偶性当前“1”数量校验位应设为
偶校验偶数4(已是偶数)0
奇校验奇数4(非奇数)1

于是:
- 偶校验时,发送1010_11000(共5字节数据 + 1位校验)
- 奇校验时,发送1010_11001

接收端收到后,也会独立计算这8位数据中有多少个“1”,然后结合接收到的校验位判断总和是否符合预设规则。如果不符,说明至少有一位出错了——这就是奇偶错误(Parity Error)

⚠️ 注意:这里说的“至少一位”,是因为如果有两位同时出错,反而可能凑巧保持奇偶性不变,从而逃过检测。这也是奇偶校验的最大局限。


它到底能防什么?不能防什么?

✅ 能可靠检测的情况

  • 单比特翻转(最常见)
  • 随机噪声引起的个别位跳变
  • 接触不良导致的某次采样失败

这类错误在实际工程中占比极高,而奇偶校验恰好能完美覆盖。

❌ 无法检测或处理的情况

  • 双比特及以上错误:如两个“1”同时翻成“0”,总数仍为偶数,无法察觉。
  • 无法纠正错误:只能标记错误,不能自动修复。
  • 不保护起始位和停止位:这些位出错会直接导致帧错误(Framing Error),不属于奇偶校验范畴。

所以别指望靠它解决所有通信问题。但它确实是物理层第一道也是最重要的一道防线


实际帧结构与硬件实现细节

UART的标准数据帧格式如下:

[起始位] [数据位 (5~9位)] [可选:奇偶校验位] [停止位(1/1.5/2位)]

当启用奇偶校验时,实际传输的数据宽度会发生变化。这一点在配置MCU外设时尤为关键。

以STM32为例,如果你使用的是8位数据 + 偶校验,那么:

huart1.Init.WordLength = UART_WORDLENGTH_8B; // 错!

看起来没错,但这是陷阱!

因为在HAL库中,UART_WORDLENGTH_8B表示“纯8位数据”,不会包含校验位。当你启用UART_PARITY_EVEN后,硬件实际上会按9位宽来收发数据(8数据 + 1校验)。因此正确的设置应该是:

huart1.Init.WordLength = UART_WORDLENGTH_9B; // 正确!

否则可能出现接收异常、DMA错位、甚至总线挂死等问题。

完整配置示例如下:

UART_HandleTypeDef huart1; void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 9600; huart1.Init.WordLength = UART_WORDLENGTH_9B; // 关键:启用校验后需设为9位 huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_EVEN; // 启用偶校验 huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } }

此时每帧共传输:1(起始)+ 8(数据)+ 1(校验)+ 1(停止)= 11位。


如何捕获并响应校验错误?

仅仅生成校验位还不够,更重要的是如何感知错误并做出反应

在STM32等现代MCU中,UART控制器会在状态寄存器中标记奇偶错误标志(PE Flag)。你可以通过轮询或中断方式处理:

方法一:轮询检测

if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_PE)) { __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_PE); Handle_Parity_Error(); // 例如记录日志、请求重传 }

方法二:开启错误中断

// 在初始化后启用错误中断 __HAL_UART_ENABLE_IT(&huart1, UART_IT_ERR); // 在中断服务程序中处理 void USART1_IRQHandler(void) { if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_PE)) { __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_PE); stats.parity_errors++; // 统计错误次数 } // 其他中断处理... }

有了这套机制,你就可以实时监控通信质量。比如连续出现多次校验错误,就可以判定链路不稳定,进而采取降速、报警、切换通道等措施。


工程实践中的那些“坑”与应对策略

🛑 坑点1:PC端串口工具未同步设置校验模式

现象:MCU明明发的是偶校验,PC上位机用“无校验”接收,结果全是乱码。

原因:PC串口驱动会严格按照设定解析每一位。如果你设了EVEN,但对方没开,那第9位就被当成下一个字节的起始位,造成后续全部错位。

✅ 解决方案:确保通信双方完全一致!常用格式如:
-9600,E,8,1→ 9600波特率,偶校验,8数据位,1停止位
-115200,O,7,2→ 更少见,用于特定协议

推荐使用支持完整格式设置的串口助手,如Tera Term、SecureCRT、CoolTerm


🛑 坑点2:误以为开启了校验就万事大吉

奇偶校验只是基础防护。真正可靠的系统还需要多层保障:

层级机制作用
物理层奇偶校验检测单比特错误
数据链路层CRC校验(如Modbus RTU)检测多比特/突发错误
应用层包头包尾、长度校验、超时重传防止协议解析崩溃

建议组合使用,形成纵深防御体系。


🛑 坑点3:性能损耗忽视

启用奇偶校验意味着每帧多传1位,在高速通信中会影响有效带宽。

对比两种常见配置:
-8N1:每字节传输10位(1起+8数+1停)→ 效率 80%
-8E1:每字节传输11位(1起+8数+1校+1停)→ 效率 ≈72.7%

相当于吞吐量下降约9%。对于音频流、图像传输等高吞吐场景,这笔账就得好好算。

但在大多数控制类应用中(如每秒几帧的传感器数据),这点代价完全可以接受。


典型应用场景举例

场景1:工业RS-485总线通信

环境恶劣,电缆长达百米,易受变频器干扰。所有设备统一采用9600,E,8,1格式。

一旦从站返回数据出现校验错误,主站立即忽略该帧并重发请求,避免脏数据入库。

场景2:医疗设备与主机通信

安全性要求极高。即使单个参数错误也可能导致误判。除奇偶校验外,还在应用层增加CRC16校验,实现双重保险。

场景3:蓝牙模块AT指令交互

像HC-05这类模块默认常为9600,N,8,1,若你强行开启校验会导致无法识别命令。此时应优先遵循模块规格书,必要时再修改其配置。


总结:小机制,大作用

回到开头的问题:为什么要关心奇偶校验?

因为它代表了一种思维方式——在资源受限的嵌入式系统中,如何用最小代价换取最大可靠性提升

它不是银弹,但它是基石。

当你设计一个新的通信链路时,请务必问自己三个问题:

  1. 我的通信环境干净吗?(实验室 vs 工业现场)
  2. 我能承受一次误码带来的后果吗?(显示错误 vs 控制失效)
  3. 我有没有其他更有效的容错手段?

如果答案偏向“不确定”或“不能承受”,那就请打开你的UART配置,认真考虑是否启用奇偶校验。

毕竟,有时候拯救系统的,不是一个复杂的算法,而是那一小小的校验位


如果你在项目中因为没开校验位踩过坑,欢迎在评论区分享经历。也欢迎点赞收藏,让更多开发者少走弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 9:15:44

PyTorch-CUDA-v2.6镜像能否用于推荐系统开发?WideDeep实战

PyTorch-CUDA-v2.6镜像能否用于推荐系统开发?Wide&Deep实战 在电商、短视频和社交平台中,用户每天面对海量内容,如何精准推送他们真正感兴趣的信息,成为产品成败的关键。推荐系统正是解决这一问题的核心引擎。而随着深度学习…

作者头像 李华
网站建设 2026/4/15 8:37:24

openmv识别物体基础实践:实现二维码与物体双识别

用OpenMV实现二维码与物体双识别:从原理到实战的完整指南你有没有遇到过这样的场景?机器人需要一边扫描二维码获取指令,一边识别前方红色障碍物进行避让。如果只能二选一,系统就显得笨拙而低效。但如果能让一个小小的摄像头同时完…

作者头像 李华
网站建设 2026/4/16 9:15:43

零基础学习USB2.0:协议架构一文说清

零基础也能懂:USB2.0协议架构全解析,从物理层到设备枚举一次讲透你有没有想过,为什么插上一个U盘,电脑就能立刻认出来?键盘一按就出字,耳机一接就能听歌——这一切看似“理所当然”的即插即用体验&#xff…

作者头像 李华
网站建设 2026/4/15 4:52:56

PyTorch-CUDA-v2.6镜像是否支持PyTorch Geometric图神经网络

PyTorch-CUDA-v2.6镜像是否支持PyTorch Geometric图神经网络 在深度学习项目中,环境配置常常比模型设计更让人头疼。尤其是当你准备动手实现一篇顶会论文中的图神经网络(GNN)时,却发现 pip install torch-geometric 报出一连串编…

作者头像 李华
网站建设 2026/4/15 21:17:27

PyTorch-CUDA-v2.6镜像运行BERT模型的内存占用优化技巧

PyTorch-CUDA-v2.6镜像运行BERT模型的内存占用优化技巧 在深度学习的实际工程中,一个常见的尴尬场景是:你精心设计好BERT微调流程,信心满满地启动训练脚本,结果几秒后终端弹出 CUDA out of memory 错误——显存炸了。尤其是当你在…

作者头像 李华
网站建设 2026/4/14 21:24:06

PyTorch-CUDA-v2.6镜像如何查看CUDA和cuDNN版本信息

PyTorch-CUDA-v2.6 镜像中如何查看 CUDA 与 cuDNN 版本 在现代深度学习开发中,一个稳定、兼容的运行环境往往比模型本身更早成为项目推进的“拦路虎”。尤其是在使用预构建的 PyTorch-CUDA-v2.6 这类集成镜像时,虽然省去了繁琐的手动配置,但随…

作者头像 李华