惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
Latest news
Latest news
P
Palo Alto Networks Blog
T
The Exploit Database - CXSecurity.com
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
AI
AI
阮一峰的网络日志
阮一峰的网络日志
量子位
Project Zero
Project Zero
Know Your Adversary
Know Your Adversary
Google Online Security Blog
Google Online Security Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
Schneier on Security
大猫的无限游戏
大猫的无限游戏
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
K
Kaspersky official blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Visual Studio Blog
Spread Privacy
Spread Privacy
C
CERT Recently Published Vulnerability Notes
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
SegmentFault 最新的问题
Hugging Face - Blog
Hugging Face - Blog
W
WeLiveSecurity
博客园 - Franky
Last Week in AI
Last Week in AI
博客园 - 聂微东
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
IT之家
IT之家
I
Intezer
The Cloudflare Blog
月光博客
月光博客
N
News | PayPal Newsroom
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
博客园_首页
罗磊的独立博客
NISL@THU
NISL@THU
爱范儿
爱范儿
Jina AI
Jina AI
有赞技术团队
有赞技术团队
The Hacker News
The Hacker News
A
Arctic Wolf
Scott Helme
Scott Helme
Engineering at Meta
Engineering at Meta
P
Proofpoint News Feed

博客园 - yooooooo

ftraceoption irq-info MPAM BE/ FE 的区别及功能 【ARM CoreLink 系列 5 -- CI-700 控制器介绍 】 ARM CoreLink 系列 4.3 -- NI-700 Component and interface identifiers ARM CCI-500 与 NI0700 的关系. ARM NIC-400 与 NI-700 的区别 claude code命令使用 【ARM Trace32(劳特巴赫) 使用介绍 2.2 -- TRACE32 进阶命令之 DIAG 弹框命令】 trace32 .cmm脚本和.t32文件的区别 【ARM Trace32(劳特巴赫) 使用介绍 2.1 -- TRACE32 Practice 脚本 cmm 脚本学习】 【ARM Trace32(劳特巴赫) 使用介绍 1.1 - Veloce 环境中使用trace32 连接 Cortex-M33】 PCIe 总线的 ASPM 和 链路状态机制总结 fw_devlink 功能 I3C协议详解 BPF 调度器 sched_ext 实现机制、调度流程及样例 Android Camera性能分析 录像Buffer Path详解 【UEFI基础】Protocol介绍 【UEFI实战】在库中使用全局变量 sched feature TTWU_QUEUE 【ARM CoreLink 系列 4.2 -- NI-700 Function units 详细介绍】 edk2构建编译流程 UEFI:FDF文件及FD、FV、FFS EDK II PCD的概念、类型、使用 PELT算法浅析 load_balance函数代码详解 UEFI Boot Manager Linux misfit task Linux 内核中sched_prio_to_weight转换关系 CFS任务放置代码详解 CFS任务的负载均衡(load balance)
UART 协议规范
yooooooo · 2026-01-17 · via 博客园 - yooooooo

1. Uart介绍

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称为UART,是一种异步收发传输器,是电脑硬件的一部分。它将要传输的资料在串行通信与并行通信之间加以转换。作为把并行输入信号转成串行输出信号的芯片,UART 通常被集成于其他通讯接口的连上。

UART 是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。在嵌入式设备中,UART 用于主机与辅助设备通信,如汽车音与外接AP 之间的通信,与PC 机通信包括与监控调试器和其它器件,如EEPOM通信。

1.1 通信协议

UART作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。 其中各位的意义如下:

  • 起始位:先发出一个逻辑”0”的信号,表示传输字符的开始。
  • 数据位:紧接着起始位之后。数据位的个数可以是5、6、7、8等,构成一个字符。通常采用ASCII码。从最低位开始传送,靠时钟定位。
  • 奇偶校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性 。
  • 停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。

由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。 因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

  • 空闲位:处于逻辑“1”状态,表示当前线路上没有数据传送。

Uart传输数据如图2-1所示:

1

2

1.2. 不同的物理层实现

由于UART协议层的输入是逻辑0/1信号,而逻辑0/1信号在物理层可以通过不同的电平标准来区分。针对不同的通讯需求,便可以使用不同的物理层实现。例如简单的板内通讯,或者常见的设备调试场景,使用简单的LVTTL/TTL电平即可在两个设备间进行UART协议通讯。

3

通用的串口则使用的是RS232电平,可以增加传输距离,并且抵抗一定程度的信号干扰。付出的成本则是在物理层需要对应的电平转换芯片来实现,发送端需要将内部的高低电平信号转换成电压更高的+/-电压信号,接收端需要将+/-电压信号转换成内部的高低电平信号。

在工业通讯的场景下,为了进一步提高传输距离,以及增强信号的可靠性,一般会采用RS485的电平标准。在发送端将普通的高低电平信号转换成一对差分信号,在接收端将差分信号再转换成普通的高低电平信号。另外,RS485允许总线上连接多达128收发器,而TTL或者RS232则是点对点的连接。

2. 协议规范

2.1. UART帧结构

在上一节的介绍中,我们通过璞石示波器观察了实际的UART波形,那么这个波形到底是怎么被准确的识别成字符‘D‘,而不是其它内容的呢?这就涉及到UART协议帧结构的定义。如图 2‑1所示:

1

当两个设备需要通过UART协议进行通讯时,它们需要同时约定好以下内容:

  • 每一位信号的时间长度T(波特率 = 1/T)
  • 帧结构中每一项的具体位数
  • 是否有校验位,以及校验位的机制(奇/偶/..)

有了这些约定,接收设备只需要等待起始位的到来,再对之后的波形进行固定间隔的采样即可获得传输的具体信息。以字符‘D‘的波形为例,其解析过程如图 2‑2所示:

4

2.2 波特率

导线 2
速度 9600、19200、38400、57600、115200、230400、460800、921600、1000000、1500000
传输方法 异步
最大主机数 1
最大从机数 1

波特率是UART协议,或者说所有异步串行协议,非常重要的一个概念,即单位时间内(1秒)可表示的bit位个数,或者也可以表述为bit位宽的倒数。例如一个波特率为115200的UART波形表示1秒可容纳115200个bit位,也就是说每一位bit数据占大约8.68uS的时长。

1

​ 图 2‑3 波特率的定义

​ UART等异步串行协议,为了简化信号物理连接,降低通讯成本,一般只有一根信号线,无法同时传输数据和时钟信号。收/发设备为了正确解析波形就需要在相同的波特率设置下。而相同的波形使用不同的波特率获取的信息可能会完全不同。对于接收设备来讲,只有起始位可以作为一帧数据的同步点,其它数据都是通过波特率来确定具体的取样位置。

还是以字符‘D’的波形为例,如图 2‑4所示,如果用错误的波特率接收,就可能会得到完全错误的数据信息。

2

​ 图 2‑4 波特率错误

2.3 空闲位

设备之间不传输数据时以持续的高电平表示空闲。空闲位持续时间越长,两个数据帧间隔也越长,单位时间传输的数据就越少。

3

​ 图 2‑5 空闲位

2.4 起始位

UART接收端会一直检测信号线上的电平变化,开始传输数据时,发送端将信号线从高电平拉到低电平结束空闲状态,并保持一个bit位的时长。接收器检测到高低电平转换时,开始接收信号。

4

​ 图 2‑6 起始位

2.5 数据位

数据位包含传输的实际数据,如果使用了奇偶校验,那么数据位长为5~8 bits,如果没有使用奇偶校验,则位长为5~9 bits。在一般情况下,数据位为 8 bits,数据首先从最低有效位开始发送,高位在后。

5

​ 图 2‑7 数据位

2.6 校验位

校验位可以用来提高传输的可靠性。如果信号在传输过程中因为干扰而导致某些位置的电平产生错误,通过计算接收的数据和校验位是否匹配即可判断数据是否有传输错误,从而给应用层提供有效信息来决定接受/丢弃对应的数据。

6

​ 图 2‑8 校验位

2.1.6. 停止位

停止位表示一帧数据的结束,实际信号是一段时间的高电平。停止位的时间长短可以设置为1、1.5或者2bits的停止位。大部分情况使用1bit的停止位。

因为UART是一个异步协议,每一帧的开头可以用跳变沿来同步,但是停止位只能通过波特率来计算相对位置,如果在停止位的位置识别到一个低电平,则会产生帧错误。在通讯过程中,为了减少波特率的误差导致的问题,可以设置不同的停止位长度来适配。

1

​ 图 2‑9 停止位

3. UART传输步骤

第一步:发送UART从数据总线并行接收数据。

1

第二步:发送UART将起始位、奇偶校验位和停止位添加到数据帧。

2

第三步:从起始位到结束位,整个数据包以串行方式从发送UART送至接收UART。接收UART以预配置的波特率对数据线进行采样。

3

第四步:接收UART丢弃数据帧中的起始位、奇偶校验位和停止位。

4

第五步:接收UART将串行数据转换回并行数据,并将其传输到接收端的数据总线。

5

4. UART 分频及波特率的关系

4.1 波特率计算公式

绝大多数 UART 的波特率都是由 输入时钟 + 分频器 生成的。

Baudrate = Fclk / (Oversample × Divider)

Fclk:UART 模块输入时钟

Oversample:过采样倍数(常见 16,也有 8、4)

Divider:分频系数(整数或整数+小数)

4.2 分频器类型

纯整数分频(最常见、最差精度)

Divider = round(Fclk / (Oversample × Baud))

生成的真实波特率:

Baud_real = Fclk / (Oversample × Divider)

特点

  • 实现简单
  • 误差可能较大
  • 对低波特率友好,对高波特率不友好

整数 + 小数分频(Fractional Divider)

常见形式:

Divider = Integer + Fraction

例如:

  • 8.25
  • 26 + 3/16
  • 52 + 1/8

PL011 示例:

Baud = Fclk / (16 × (IBRD + FBRD / 64))

特点

  • 波特率精度大幅提升
  • 成本略高(需要小数累加器或调制器)

小数调制(NCO / DDS 型)

Baud = Fclk × N / 2^k
  • 本质是数控振荡器
  • 精度极高
  • 常用于高速 UART / 调试串口

4.3 波特率误差的定义

Error (%) = (Baud_real - Baud_target) / Baud_target × 100%

4.4 UART 能容忍的最大误差

原因

UART 是 异步通信,靠起始位对齐,之后靠本地时钟采样。

理论极限(8N1)

  • 一帧:
    1 start + 8 data + 1 stop = 10 bit
  • 允许在 stop bit 采样前不漂移到下一个 bit

常见结论(工程经验)

情况 最大允许误差
单端误差(一边理想) ±5%
双端都有误差 ±2% ~ ±3%
稳妥设计 ≤ ±1%

这是累积误差,不是瞬时抖动

4.5 实例计算

示例 1:24 MHz 时钟,115200 bps,16 倍过采样

目标分频

Divider = 24,000,000 / (16 × 115200) ≈ 13.0208

整数分频

Divider = 13
Baud_real = 24,000,000 / (16 × 13) ≈ 115384
Error ≈ +0.16%

✔ 完全没问题

示例 2:48 MHz 时钟,921600 bps

Divider = 48,000,000 / (16 × 921600) ≈ 3.255
  • 取 3 → 1,000,000 (+8.5%) ❌
  • 取 4 → 750,000 (−18.6%) ❌

整数分频完全不可用

必须:

  • 降低 oversample(16 → 8)
  • 使用 fractional divider
  • 换 UART 时钟源