Skip to content

打包与解包

在串口通信(UART)中,我们在物理线路上确实传输了比实际数据更多的位,而单片机内部的**硬件外设(USART 模块)**帮我们完成了所有的“打包”和“解包”工作。软件(CPU)只需要关心那核心的 8 位数据。

我们可以把它拆解为三个层面来看:

1. 物理层:实际发送了什么?(总共有 10~11 位)

假设我们配置为最常用的 “8N1” 模式(8位数据,无校验,1位停止位):

  • 1 位 起始位(Start Bit)
  • 8 位 数据位(Data Bits,这就是你想传的“干货”)
  • 0 位 校验位(No Parity)
  • 1 位 停止位(Stop Bit)
  • 总计:1 + 8 + 0 + 1 = 10 位

这意味着,为了传送一个字节(8 bit),总线上必须忙活 10 个时钟周期。 这就是为什么串口的实际传输速度(有效数据率)只有波特率的 80% 左右。

2. 硬件层:单片机内部在做什么?(自动剥壳)

这是 STM32 或其他单片机内部 USART 硬件模块最厉害的地方,它就像一个 全自动剥虾机

  1. 串行移位(Serial Shift): 接收引脚(RX)检测到下降沿(起始位)后,硬件开始工作,按照波特率的节奏,一位一位地把这 10 位电平读进来,塞到一个临时的移位寄存器里。
  2. 验证(Validation): 硬件会检查第一位是不是低电平(起始位),最后一位是不是高电平(停止位)。如果不是,它会置位一个错误标志(如 FE - Framing Error)。
  3. 剥离(Stripping): 如果格式正确,硬件会自动 扔掉起始位,扔掉停止位,如果有校验位,它也会根据校验位计算数据是否正确(如果不正确置位 PE - Parity Error)。
  4. 入库(Store): 最后,它只把中间那 8 位纯净的数据,并行地“啪”一下复制到**数据接收寄存器(如 STM32 的 RDR 或 DR)**中。
  5. 通知(Interrupt/Flag): 做完这一切,硬件举起小旗子(设置 RXNE 标志位)或触发中断,告诉 CPU:“老板,虾剥好了,只有虾仁,快来拿!”

3. 软件层:你看到了什么?

当你在写代码时(比如 data = USART1->RDR;HAL_UART_Receive(...)),你读到的:

  • 完全看不到 起始位。
  • 完全看不到 停止位。
  • 通常看不到 校验位(除非配置了 9 位模式且需要手动处理)。

你读到的就是一个干净的 0x550xA1