UART通信基础知识

UART 经常被当成“接上 TX、RX 就能用”的接口。

真正排查乱码、偶发丢字或半双工冲突时,问题可能分布在完全不同的层:

  • MCU 引脚的逻辑电平不兼容;
  • RS-232 或 RS-485 收发器接错;
  • 数据位、校验位或停止位配置不同;
  • 分频器产生的实际波特率有误差;
  • 接收采样点在一帧内逐渐漂移;
  • FIFO 没有及时清空,发生硬件 overrun;
  • 字节都收对了,但上层协议失去帧边界。

这篇按这几层逐步拆开。

文中的波形和误差区域由明确的理想模型生成,不是逻辑分析仪截图。
附件会复算文章里的数值;器件的真实采样规则、容差和错误标志,仍以对应型号的数据手册为准。

先把“串口”的几个层次分开

UART 是 Universal Asynchronous Receiver/Transmitter。
它是把并行数据转换成异步串行比特流、再把接收比特流还原为数据字的硬件模块。

UART 主要定义这些内容:

  • 空闲、起始、数据、校验和停止位的时序;
  • 数据位宽和低位先发等规则;
  • 发送、接收寄存器或 FIFO;
  • 波特率发生器、采样器和错误标志。

UART 本身不等于 RS-232,也不等于 RS-485。

UART 逻辑帧经不同收发器转换为逻辑电平、RS-232 或 RS-485 信号

三者处在不同层次:

名称 主要解决的问题 典型信号
MCU 逻辑 UART 字节怎样变成异步串行帧 TXD、RXD,逻辑 0/1
RS-232 单端线路上的电压、极性和接口 TX、RX、GND,经专用收发器
RS-485 差分、多点线路与驱动使能 A、B,常见 DE、RE 控制
上层协议 字节流如何划分消息、校验和重传 长度、转义、CRC、序号等

把 USB 转 TTL、USB 转 RS-232 和 USB 转 RS-485 都叫“串口线”,不代表它们能互换。

逻辑电平 UART

MCU 的 UART 引脚通常是芯片 I/O 电平,例如 1.8 V、3.3 V 或 5 V。
输入高低阈值、是否 5 V tolerant、上电默认状态都应查具体数据手册。

普通非隔离连接通常至少需要:

1
2
3
设备 A TX  -> 设备 B RX
设备 A RX <- 设备 B TX
设备 A GND -- 设备 B GND

UART 交叉接线与公共参考地,供电单独处理

VCC 不能因为针脚名字一样就直接相连。
两块板已经各自供电、工作电压不同,或者接口带隔离时,VCC 的处理会完全不同。

只监听目标输出时,可以只接目标 TX、采集设备 RX 和参考地。
要进行双向通信,TX 和 RX 才都需要交叉连接。

RS-232 不是“更高电压的 TTL UART”

RS-232 在线缆侧使用正负电压,并且线路逻辑通常相对 MCU UART 引脚反相。
MCU 引脚不能直接接到 RS-232 线上。

Analog Devices 的 RS-232 说明给出的接口边界很清楚:
UART 负责起始、停止、校验和串并转换,RS-232 line driver/receiver 负责电平转换与线路侧驱动。

看到 DB9 接头也不能只凭外形判断针脚定义。
DTE/DCE、直连线与交叉线、是否使用 RTS/CTS,都要结合设备文档和实测确认。

RS-485 还多了总线方向问题

RS-485 使用差分线路,常见两线制是半双工。
UART TXD/RXD 仍是逻辑信号,A/B 由 RS-485 收发器驱动和接收。

半双工发送通常还要控制 DE:

  1. 置 DE,等待驱动器进入发送状态;
  2. 向 UART 写入整帧;
  3. 等最后一个停止位真正离开移位寄存器;
  4. 再释放 DE,让其他节点发送。

“发送数据寄存器空”只说明可以继续写下一个字,不一定说明线上最后一位已经完成。
切换 DE 时应使用外设的 transmission complete 条件,而不是只看 TX empty。

Analog Devices AN-960还说明了多点总线的三态驱动、终端、偏置和空闲 fail-safe。
终端电阻不是“有 RS-485 就随便加一个”;位置、线缆阻抗、总线长度和拓扑都要一起判断。

另外,不同厂商对 A/B、+/− 的命名习惯可能造成混淆。
接线时应核对收发器数据手册中的 truth table,不能只按字母颜色连接。

UART 帧:先算清每个字节到底占多少时间

常见非反相 UART 在空闲时为高电平。
一次帧通常包含:

1
Start | Data bits (LSB first) | optional Parity | Stop

115200 8N1 表示:

  • 目标波特率 115200;
  • 8 个数据位;
  • N:无 parity;
  • 1 个停止位。

在普通二进制 UART 中,一个符号承载一个 bit,所以 baud 数值与 bit/s 数值相同。
这不表示应用层每秒能传 115200 个有效数据 bit,因为起始、校验和停止位也占时间。

设:

  • 数据位数为 D;
  • 有 parity 时 P=1,否则 P=0;
  • 停止位长度为 S;
  • 波特率为 B。

一帧的 bit 数和时间为:

1
2
N_frame = 1 + D + P + S
T_frame = N_frame / B

对 8N1:

1
2
3
N_frame = 1 + 8 + 0 + 1 = 10 bit
T_byte = 10 / 115200 = 86.8056 μs
R_byte = 115200 / 10 = 11520 byte/s

它在线路层已经有 20% 的非数据开销。

8E1 或 8N2 都是每帧 11 bit:

1
115200 / 11 = 10472.727 byte/s

如果协议每 64 字节还加 8 字节头尾,有效负载率还要乘:

1
64 / (64 + 8) = 88.89%

RTS/CTS 等流控、RS-485 换向保护时间、帧间空闲以及重传都会继续降低吞吐。

手工解一个 0x53

0x53 的通常二进制写法是 01010011。
UART 数据位一般低位先发,所以线上 D0 到 D7 是:

1
1 1 0 0 1 0 1 0

加上 8N1 的起始和停止位:

1
2
Start | D0 D1 D2 D3 D4 D5 D6 D7 | Stop
0 | 1 1 0 0 1 0 1 0 | 1

0x53 在 8N1 下的波形与每一位的采样中心

停止位不要求一定出现新的上升沿。
如果最后一个数据位本来就是 1,线路可以从 D7 一直保持高到停止位和下一段空闲。

parity 能发现什么

偶校验要求数据位和 parity 位中 1 的数量为偶数;奇校验要求总数为奇数。

0x53 有四个 1:

  • 8E1 的 parity 位是 0;
  • 8O1 的 parity 位是 1。

一次奇数个 bit 翻转通常会改变 parity。
两个 bit 同时翻转可能互相抵消,所以 parity 不能替代消息级 CRC。
它也不能指出哪个 bit 错了,更不能提供消息认证。

某些外设的“9 bit 模式”会把第九位用作普通数据、地址标记或 parity,具体寄存器语义并不统一。
读取数据寄存器时也要确认 parity 位是否被硬件剥离。

接收器怎样从一个起始沿恢复采样时刻

异步链路没有共享时钟。
接收器看到空闲高到起始低的下降沿后,用自己的时钟安排后续采样。

一种常见实现是 16× oversampling:

  1. 检测起始下降沿;
  2. 在起始位中间验证它仍为低;
  3. 之后每隔 16 个采样 tick 读取下一位;
  4. 在停止位位置期望读到高电平。

Microchip 的采样调整文档给出了一个具体实现:
16× 模式下使用第 7、8、9 个样本做多数表决;8× 模式使用第 3、4、5 个样本。

这只是一个可核对的器件实现,不是所有 UART 必须采用的算法。
其他外设可能使用单点采样、不同的多数表决位置、数字滤波或边沿再同步。

起始检测也有量化误差

数据下降沿与接收器采样时钟是异步的。
下降沿刚好落在两个采样 tick 之间时,接收器只能在后续 tick 识别它。

在理想 16× 模型中,这个初始误差可接近一个 oversample tick:

1
2
T_tick = T_rx / 16
0 <= δ_phase < T_tick

若以起始位为第 0 个 cell,并在每个 cell 中央采样,中心位置近似为:

1
t_k = t_detect + (8 + 16k) × T_tick

其中 k=0 是起始位中心,k=1 是 D0,k=9 是 8N1 的停止位中心。

波特率误差为何在一帧内累积

发送端和接收端只在起始沿附近重新对齐一次。
若两边 bit period 不同,之后每一位都会再增加一点偏移。

用一阶近似表示第 k 个 cell 中心的偏移:

1
Δt_k ≈ δ_phase + (k + 0.5) × (T_rx - T_tx)

帧越长,最后一个数据位和停止位越容易靠近相邻 bit 的边界。

时钟误差在同一 UART 帧内逐位累积

误差在停止位后不会无限积累。
下一帧新的起始沿会重新同步;真正需要覆盖的是一帧内的最坏位置。

为什么不能背一个“允许相差 10%”

理想情况下,中心采样点偏移半个位就会碰到边界。
真实链路却不能一直用到边界:

  • 起始检测有相位量化;
  • 上升、下降沿需要时间;
  • 阈值、噪声和抖动会减少稳定窗口;
  • 多数表决位置与滤波规则影响边界;
  • 数据位数、parity 和停止位改变一帧长度;
  • 接收器和发送器的时钟误差都要计入。

Analog Devices 的 UART 时钟精度分析在明确假设下给出两个示例:
可靠采样窗口取 bit 中部 75% 时,10-bit frame 的预算约为 ±3.3%;窗口只有中部 50% 时约为 ±2%。

这些数字来自对应模型,不是跨芯片通用的“UART 标准容差”。

工程上更可靠的做法是建立预算表:

1
2
3
4
5
链路相对误差
≈ 接收器时钟误差
- 发送器时钟误差
+ 两边波特率分频误差
+ 短期抖动与检测误差余量

只知道“双方都设置成 115200”不够,还要知道它们实际产生了多少。

一个可运行的 16× 理想采样实验

下载 uart_timing_lab.py:

1
python3 uart_timing_lab.py --svg uart-sampling-simulation.svg

模型使用:

  • 瞬时、无振铃的理想边沿;
  • 固定的发送端 bit period;
  • 接收端固定频差;
  • 起始检测延迟在一个接收 oversample tick 内变化;
  • 第 7、8、9 个 tick 三点多数表决;
  • 测试字节 0x55,使相邻数据位频繁翻转。

Python 理想模型生成的 0x55 采样漂移与成功区域

本次使用 Python 3.11 运行得到:

1
2
3
4
5
6
7
8
model: ideal edges, fixed frequency error, 16x vote at ticks 7/8/9
frame 0x55: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
ideal all-phase pass interval: -4.85% .. +5.55% RX rate error
integer divider: N=26, actual=115384.615385, error=+1602.56 ppm
1/64 fractional divider: REG=1667 (N=26.046875), actual=115176.964607, error=-199.96 ppm
115200 8N1 byte time: 86.8056 us
16-byte FIFO no-service window: 1.3889 ms
256-byte ring no-consumer window: 22.2222 ms

-4.85%..+5.55% 只属于这段代码的理想边沿、0x55、三点采样和相位扫描。
区间不对称,是因为模型把起始沿检测延迟定义为 [0, 1) 个接收 tick,并从检测时刻向后安排采样。

它没有模拟:

  • 输入阈值和迟滞;
  • 传播延迟与上升下降时间;
  • 随机噪声、周期抖动和突发干扰;
  • 接收器内部滤波或重同步;
  • 收发器、隔离器与线缆的失真。

因此,这张图适合解释“误差怎样积累”,不适合作为选型时的最大容差。

波特率发生器:设置值不等于实际值

整数分频

假设 UART 输入时钟为 f_clk,16× 模式使用整数分频 N:

1
2
B_actual = f_clk / (16 × N)
N_ideal = f_clk / (16 × B_target)

以 48 MHz 和 115200 为例:

1
2
3
4
5
6
N_ideal = 48000000 / (16 × 115200)
= 26.041666...

N = round(N_ideal) = 26
B_actual = 48000000 / (16 × 26)
= 115384.615385

误差同时用百分比和 ppm 表示:

1
2
3
error = (B_actual - B_target) / B_target
= +0.160256%
= +1602.56 ppm

1/64 小数分频示例

Microchip 的 fractional baud generator 文档描述了低 6 bit 保存分频小数部分的实现。

若把理想分频值乘 64 后取整:

1
2
3
4
5
6
7
BAUD = round(26.041666... × 64) = 1667
N_fractional = 1667 / 64 = 26.046875

B_actual = 64 × 48000000 / (16 × 1667)
= 115176.964607

error = -199.96 ppm = -0.019996%

小数分频把本例的量化误差从约 1603 ppm 降到约 200 ppm。
寄存器公式、舍入规则、oversampling 模式和允许范围依芯片而异,不能把这里的 1667 写到另一类外设。

时钟源误差仍然存在

波特率寄存器只解决分频量化。
晶振、RC 振荡器、PLL 和外设时钟树还会带来:

  • 初始频率误差;
  • 温度漂移;
  • 电压与老化影响;
  • PLL 或时钟切换产生的抖动;
  • 低功耗模式下时钟源变化。

两个端点误差方向相反时,链路相对误差会变大。
做最坏情况预算时,应组合两边数据手册给出的边界,而不是只加典型值。

自动波特率检测也不是无限容错。
它依赖特定同步字符或边沿模式,得到的计数仍受输入边沿、时钟量化和实现规则影响。

Framing、Parity、Noise 与 Overrun 不是一类错误

接收端经常暴露多个独立标志:

标志 硬件观察到的现象 常见方向
Framing error / FE 在期望的停止位位置读到低 波特率、位宽、反相、break、噪声
Parity error / PE 数据与 parity 不满足配置 parity 配置不同或 bit 受干扰
Noise error / NE 多点采样不一致或检测到噪声 信号完整性、阈值、线缆与地
Overrun / ORE 新数据到达时前一数据未被取走 FIFO、IRQ 延迟、DMA 或软件阻塞
IDLE 接收线在规定时间没有新帧 可作为通知,不天然等于协议结尾
Break 线路持续低电平超过普通字符时间 break 信号、短路、错误极性等

ST 的 LPUART 培训资料分别列出 overrun、parity、framing 和 noise 标志,也说明 RX ready、IDLE 和 DMA 请求属于不同事件。

Framing error

FE 的直接含义是停止位检查失败。
可能原因包括:

  • 两端波特率差太大;
  • 8N1 与 7E1 等帧配置不一致;
  • 线路反相;
  • 起始位是噪声尖峰;
  • break 持续低电平覆盖停止位;
  • 边沿太慢或采样窗口被噪声侵入。

FE 不等于“某个文本字符编码错了”。
错误发生在 UART frame 层。

Parity error

PE 表示硬件计算出的 parity 与接收 parity 位不一致。
如果一端 8N1、另一端 8E1,后续 bit 边界也可能被错误解释,同时出现 PE 或 FE。

记录错误时应保存原始数据字和状态寄存器读取顺序。
部分外设在读取状态或数据寄存器后清除标志,具体步骤必须查参考手册。

Overrun

ORE 与线路采样可能完全无关。
字节已经正确到达外设,但软件没有及时腾出接收寄存器或 FIFO。

如果“刚开始正常,持续大流量后才丢字”,优先观察:

  • 中断是否被高优先级任务长时间屏蔽;
  • ISR 是否做了日志格式化或阻塞 I/O;
  • FIFO 阈值是否留下足够余量;
  • DMA 是否处于 circular 模式;
  • 环形缓冲的 consumer 是否跟得上 producer;
  • 错误回调是否停止了接收却没有重新启动。

FIFO、IRQ、DMA 与环形缓冲的时间预算

UART 接收数据从采样器、FIFO、DMA 到有界解析器的路径

设一帧占 N_frame bit,波特率为 B:

1
T_byte = N_frame / B

如果硬件 FIFO 还有 F_free 个空位,软件完全不服务的理论上限是:

1
T_fifo = F_free × T_byte

115200 8N1、FIFO 还有 16 个空位:

1
2
T_fifo = 16 × 10 / 115200
= 1.3889 ms

这不是允许 ISR 延迟 1.3889 ms 的承诺。
真实预算还要扣除:

  • 中断触发阈值已经占用的 FIFO 空间;
  • 当前字符仍在移入;
  • 总线和 DMA 竞争;
  • 临界区、关中断区间与调度抖动;
  • 错误处理和缓存一致性开销。

每字节中断

优点是简单、延迟低。
缺点是高波特率下中断频繁,ISR 稍重就可能抖动或 overrun。

ISR 最好只做有界操作:

1
2
3
4
5
6
读取状态
读取数据
写入 ring buffer
递增错误计数
唤醒解析任务
返回

不要在接收 ISR 中执行 JSON 解析、printf、Flash 写入或等待互斥锁。

FIFO 阈值中断

FIFO 可以降低中断频率,但阈值越高,触发时剩余空间越少。
选择阈值时要同时看吞吐和最坏中断延迟。

高阈值不自动提高可靠性。
如果一次 ISR 只取一个字节,反而可能一直处于临界状态。

Circular DMA + ring buffer

DMA 可以持续把 RDR 数据搬到内存,但 DMA 数组本身仍是有限环。
软件要维护“DMA 已写到哪里”和“解析器已读到哪里”。

一个常见思路是:

1
2
3
4
5
write_pos = (buffer_size - dma_remaining) % buffer_size

while read_pos != write_pos:
consume(buffer[read_pos])
read_pos = (read_pos + 1) % buffer_size

工程实现还要处理:

  • 读取 DMA 计数时的竞态;
  • HT、TC、IDLE 回调可能连续发生;
  • cacheable 内存上的一致性;
  • consumer 落后一整圈时怎样识别;
  • 溢出后丢新数据、丢旧数据还是重置协议;
  • 多核或 ISR/任务之间的内存顺序。

只用取模后的 head == tail 无法区分空缓冲和整圈覆盖。
可以保留一个空槽、维护单调递增计数,或额外记录 generation。

ST 官方的 Receive-to-IDLE Circular DMA 示例展示了 HT、TC 和 IDLE 三类通知以及回调中的索引含义。
示例中的 IDLE 是接收线在最后一个字节后保持一个 frame time 空闲触发。

IDLE 很适合通知“当前有一批字节可处理”,但它不是普适消息边界:

  • 协议允许消息内部停顿时,IDLE 会提前出现;
  • 连续消息之间没有空闲时,IDLE 不会分开它们;
  • 调度延迟会让多个事件在处理时合并。

UART 只提供字节流,上层必须自己定义消息

假设连续收到:

1
01 10 00 05 00 07 41 7E 42 7D 43 36 56

UART 不知道:

  • 第一个字节是不是帧头;
  • 00 05 是不是长度;
  • 7E 是数据还是分隔符;
  • 最后两个字节是不是 CRC;
  • 一次 read 返回的是半帧、一帧还是多帧。

应用协议必须选一种可重同步的结构。

方法 优点 主要风险
固定长度 状态最简单 扩展困难,错一字节后需要外部重同步
分隔符 人类可读,容易找边界 数据中出现分隔符时需要转义
长度字段 支持二进制和变长 payload 损坏长度可导致等待过久或越界
空闲间隔 某些总线协议实现方便 调度和链路停顿可能破坏边界
编码帧,如 COBS 边界明确,开销可控 双方必须实现同一编码规则

实际协议常组合:

1
SOF + header(length/sequence/type) + escaped payload + CRC

一个有界、可重同步的解析示例

下载 uart_packet_parser.py。

示例定义如下,不把“CRC16”写成含糊名字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
start delimiter : 0x7E
escape byte : 0x7D
escaped value : original XOR 0x20

unescaped body:
version:u8 | type:u8 | payload_len:u16be | sequence:u16be | payload | crc:u16be

CRC-16/CCITT-FALSE:
width = 16
poly = 0x1021
init = 0xFFFF
refin = false
refout = false
xorout = 0x0000
check("123456789") = 0x29B1

解析器在读到长度后立即检查:

1
2
3
4
payload_len = int.from_bytes(body[2:4], "big")
if payload_len > MAX_PAYLOAD:
length_errors += 1
reset()

这一步必须发生在:

  • 按长度分配内存之前;
  • 等待剩余 payload 之前;
  • 进行 header + length 算术而未检查溢出之前。

收到新的 0x7E 时,解析器丢弃未完成旧帧并重新开始。
CRC 错误和超长长度不会让它无限缓存数据。

运行:

1
python3 uart_packet_parser.py

本次输出:

1
2
3
4
5
CRC check vector: 123456789 -> 0x29B1
escaped frame seq=7: 7e 01 10 00 05 00 07 41 7d 5e 42 7d 5d 43 36 56
accepted: type=0x10 seq=7 payload=b'A~B}C'
accepted: type=0x11 seq=10 payload=b'recovered'
counters: accepted=2 crc_errors=1 length_errors=1 restarts=1

测试流故意包含:

  • 分块输入,模拟一次 read 只返回部分字节;
  • payload 内的 0x7E 和 0x7D;
  • 一帧 CRC 损坏;
  • 一个超出 MAX_PAYLOAD 的长度;
  • 一帧被截断后又出现新 SOF;
  • 噪声之后的两个合法帧。

CRC 能发现常见传输错误,但不提供认证。
攻击者可以修改数据并重算 CRC;有对抗性需求时应使用经过审查的消息认证或 AEAD 设计,并同时考虑重放和密钥管理。

解析器的工程边界

不要把一次 read 当成一帧

无论是串口驱动、DMA 回调还是操作系统 read():

  • 可能只返回半个 header;
  • 可能返回恰好一帧;
  • 可能一次返回三帧再加下一帧开头。

正确解析器应跨调用保存状态,并在一个 chunk 中循环取出所有完整帧。

为每个等待状态设置上限

除了 MAX_PAYLOAD,还可记录:

  • 从 SOF 开始已经接收的字节数;
  • 当前帧开始时间;
  • 连续 escape 的异常情况;
  • CRC、长度和重同步计数;
  • 序号跳变与重复帧。

若协议允许长时间停顿,timeout 不能替代长度与容量边界。
timeout 只是另一项状态清理策略。

错误后如何恢复要写进协议

只说“CRC 错就丢包”还不完整。
还要说明下一步怎样找到新边界:

  • 等待下一个未转义 SOF;
  • 丢弃固定长度;
  • 使用编码保证分隔符唯一;
  • 通过序号确认是否需要重传。

如果帧头可能自然出现在未转义 payload 中,扫描一个 magic 值并不能可靠重同步。

从症状反推层次

完全没有字节

依次确认:

  1. 目标是否真的发送;
  2. 测量点是在 MCU 逻辑侧还是收发器线路侧;
  3. TX/RX 是否交叉;
  4. 是否共地或正确隔离;
  5. 逻辑电平、反相和收发器使能;
  6. 引脚复用与外设时钟;
  7. RS-485 DE/RE 和总线偏置。

每个字节都像固定变换后的乱码

检查:

  • 线路是否反相;
  • 7/8/9 数据位和 parity 是否不同;
  • bit order 是否被上层错误解释;
  • 终端是否把二进制当 UTF-8 或 GBK 显示;
  • 实际波特率而不只是配置值。

先保存十六进制原始字节。
终端显示不正常,不等于 UART 解码错误。

前面正确,越到帧尾越容易错

这很像采样时钟差在帧内积累。
测量多个 bit 宽度、计算双方实际分频、查看 FE,并与器件容差表比较。

不要只测一个低脉冲。
连续几个相同 bit 会合并成更宽的电平区间,看起来像一个“很慢的 bit”。

低流量正常,持续流量丢字

优先看 ORE、FIFO watermark、最大关中断时间、DMA 环覆盖和解析任务吞吐。

可以给每一级留计数器:

1
2
3
4
5
6
7
8
9
uart_fe
uart_pe
uart_ne
uart_ore
dma_wrap
ring_overflow
protocol_length_error
protocol_crc_error
protocol_resync

把硬件错误和协议错误分开计数,才知道该换探头、改时钟还是改软件。

RS-485 只在自己发送后出错

检查:

  • DE 是否过早释放,截断最后停止位;
  • DE 是否太晚释放,与对端响应冲突;
  • 本机接收器是否回读自己的发送;
  • 多节点是否同时驱动;
  • 终端和偏置是否合适;
  • 协议是否规定 turnaround 时间。

用 TX complete 而不是 TX register empty 判断最后一位发完。

采集与复现时应记录什么

一次能复核的 UART 问题记录至少包括:

1
2
3
4
5
6
7
8
测量位置:MCU TXD/RXD 侧,还是 RS-232/RS-485 线缆侧
硬件:MCU、收发器、隔离器、线缆长度、终端与偏置
配置:外设时钟、baud 寄存器、oversampling、data/parity/stop
方向:全双工,或 RS-485 DE/RE 时序
采集:逻辑分析仪采样率、阈值、探头参考地
软件:FIFO 深度与阈值、IRQ 优先级、DMA 模式、ring 大小
错误:FE/PE/NE/ORE 与协议错误计数
原始数据:带时间戳的十六进制,不只保留终端文本

逻辑分析仪采样率应足够高,阈值也要与测量侧电平匹配。
软件 UART decoder 的自动 baud 猜测只能作为线索,最好用长采样中的多个边沿复算 bit period。

在 RS-232 或 RS-485 线路侧采集时,普通逻辑分析仪可能既不耐受电压范围,也不能正确解释差分信号。
应使用相应探头、接收器或在线路收发器逻辑侧测量。

本文实验的可复核边界

项目 本文做了什么 没有声称什么
8N1 波形 从确定 bit 序列绘制 不是实物采样
16× timing lab 扫描固定频差与检测相位 不是芯片最大容差
baud divider 复算 48 MHz 的整数与 1/64 示例 不代表其他寄存器格式
FIFO 时间 按完全无人消费计算理论窗口 不代替实时调度分析
packet parser 测试分块、转义、CRC、长度和重同步 CRC 不提供认证
RS-232/RS-485 说明收发器与控制边界 不给具体板卡接线结论

附件使用标准库,可在没有串口硬件时复算:

真正接入设备后,应把理想模型替换为:

  • 目标 MCU 参考手册中的采样与容差公式;
  • 时钟源在电压、温度和寿命范围内的误差;
  • 收发器、隔离器、终端和线缆参数;
  • 设备上观测到的错误标志、DMA 指针和原始波形。

参考资料


UART通信基础知识
https://g1at.github.io/2023/09/10/UART/
作者
g0at
发布于
2023年9月10日
许可协议