目录
- 前言
- 一、串口通信中的速率协调问题
-
- [1.1 为什么串口通信会"鸡同鸭讲"?](#1.1 为什么串口通信会“鸡同鸭讲”?)
- 二、比特率:衡量信息传输速度的标尺
-
- [2.1 比特率的定义与单位](#2.1 比特率的定义与单位)
- [2.2 生活中的实例:千兆带宽的真相](#2.2 生活中的实例:千兆带宽的真相)
-
- [2.2.1 详细的换算推导](#2.2.1 详细的换算推导)
- 三、波特率:串口通信的"心跳"
-
- [3.1 波特率 vs 比特率](#3.1 波特率 vs 比特率)
-
- [3.1.1 "扔球游戏"通俗原理解析](#3.1.1 “扔球游戏”通俗原理解析)
- [3.2 波特率在波形上的体现](#3.2 波特率在波形上的体现)
- 四、如何确立通信握手
-
- [4.1 历史遗留的标准数值](#4.1 历史遗留的标准数值)
- [4.2 解决通信失败的关键:约定一致](#4.2 解决通信失败的关键:约定一致)
- 五、帧格式约定
-
- [5.1 为什么必须约定"帧格式"?](#5.1 为什么必须约定“帧格式”?)
- [5.2 标准 USART 数据帧的解剖](#5.2 标准 USART 数据帧的解剖)
-
- [5.2.1 传输顺序详解:LSB First 与 MSB First](#5.2.1 传输顺序详解:LSB First 与 MSB First)
-
- [什么是 LSB?](#什么是 LSB?)
- [什么是 MSB?](#什么是 MSB?)
- [在 USART 中的实际应用](#在 USART 中的实际应用)
- [5.3 传输过程的量化计算](#5.3 传输过程的量化计算)
- 结语


🎬 云泽Q :个人主页
🔥 专栏传送入口 : 《C语言》《数据结构》《C++》《Linux》《蓝桥杯系列》《笔试算法》《AI赋能》《STM32》《Python》
⛺️遇见安然遇见你,不负代码不负卿~
前言
大家好啊,我是云泽Q,欢迎阅读我的文章,一名热爱计算机技术的在校大学生,喜欢在课余时间做一些计算机技术的总结性文章,希望我的文章能为你解答困惑~
一、串口通信中的速率协调问题
1.1 为什么串口通信会"鸡同鸭讲"?
在嵌入式开发中,我们经常会遇到一种看似玄学的问题:明明 MCU(微控制器)和外部串口设备之间的物理连线完全正确,TX 接 RX,RX 接 TX,地线 GND 也共用了,但就是无法正常通信,或者接收到的数据全是乱码。这就是双方虽然建立了连接通道,但如果双方在沟通的节奏上没有达成默契,信息就无法被正确理解。
这就引出了串口通信中最核心的一个概念:速率协调。
想象一下这个场景:MCU 作为一个发送方,它的工作节奏非常快,每 1 秒就能发送 8 个高低电平信号;而接收端的串口设备却是一个"慢性子",它以为对方是每 2 秒才发送一个信号。结果就是,当 MCU 已经发完了 8 个数据时,接收端才刚刚读完第 4 个数据。这种收发步调的不一致,直接导致了数据的丢失和错乱。

要解决这个问题,我们必须引入一个能够量化"快慢"的标准。在 USART(通用同步异步收发器)通信中,这个标准就是波特率 。但在深入讲解波特率之前,为了避免概念混淆,我们需要先厘清另一个经常与之相伴的概念------比特率。
二、比特率:衡量信息传输速度的标尺
2.1 比特率的定义与单位
所谓的比特率,指的是每秒钟传送的**比特位(bit)**的个数。它也被称为"传信率",侧重点在于衡量有效信息的传输速度。
- 基本单位 :
bit/s或bps(bits per second)。 - 常用倍数单位 :
Kbit/s、Mbit/s、Gbit/s。
这里有一个极其重要且容易被程序员搞混的细节:在描述比特率时,这里的 K、M、G 遵循的是十进制换算规则,而非计算机存储中习惯的二进制规则。
- 十进制(通信领域) : 1 K = 1000 1\text{K} = 1000 1K=1000, 1 M = 1 , 000 , 000 ( 10 6 ) 1\text{M} = 1,000,000 (10^6) 1M=1,000,000(106), 1 G = 1 , 000 , 000 , 000 ( 10 9 ) 1\text{G} = 1,000,000,000 (10^9) 1G=1,000,000,000(109)。
- 二进制(存储领域) : 1 K = 1024 ( 2 10 ) 1\text{K} = 1024 (2^{10}) 1K=1024(210), 1 M = 1024 × 1024 ( 2 20 ) 1\text{M} = 1024 \times 1024 (2^{20}) 1M=1024×1024(220)。
2.2 生活中的实例:千兆带宽的真相
为了让大家更直观地理解比特率,我们来看一个生活中最常见的例子------家里的宽带网络。
当你去办理宽带业务时,运营商会宣传这是"千兆带宽"。这里的"千兆",指的就是 1000 Mbit/s 。请注意,这里使用的是小写的 b (bit),而不是大写的 B (Byte)。
- 小写 b (bit):比特位,信息的最小单位。
- 大写 B (Byte):字节,1 Byte = 8 bits。
2.2.1 详细的换算推导
让我们通过一个具体的计算过程,来看看 1000M 带宽到底意味着什么。
-
理论峰值计算(十进制转十进制) :
1000 Mbit/s ÷ 8 = 125 MB/s 1000 \text{ Mbit/s} \div 8 = 125 \text{ MB/s} 1000 Mbit/s÷8=125 MB/s
这里的 M 依然是 10 6 10^6 106。也就是说,理论上你的网卡每秒最大能吞吐 125 × 10 6 125 \times 10^6 125×106 个字节。
-
程序员视角的换算(转换为二进制单位) :
我们在操作系统中看到的文件大小通常是基于二进制的(即 MiB,虽然常显示为 MB)。
- 首先将总比特数算出: 1000 × 10 6 bit 1000 \times 10^6 \text{ bit} 1000×106 bit
- 转换为 Kbit (二进制): ( 1000 × 10 6 ) ÷ 1024 ≈ 976 , 562 Kbit (1000 \times 10^6) \div 1024 \approx 976,562 \text{ Kbit} (1000×106)÷1024≈976,562 Kbit
- 转换为 Mbit (二进制): 976 , 562 ÷ 1024 ≈ 953 Mbit 976,562 \div 1024 \approx 953 \text{ Mbit} 976,562÷1024≈953 Mbit
- 最后转换为 Byte (字节): 953 ÷ 8 ≈ 119 MB/s 953 \div 8 \approx 119 \text{ MB/s} 953÷8≈119 MB/s (此处指 MiB/s)
所以,当你拥有 1000M 带宽时,理论上的最高下载速度大约是 119 MB/s。
- 实际下载时间估算 :
假设你要下载一部大小为 2GB(即 2 × 1024 = 2048 MB 2 \times 1024 = 2048 \text{ MB} 2×1024=2048 MB)的电影。
所需时间 = 2048 MB 119 MB/s ≈ 17.2 秒 \text{所需时间} = \frac{2048 \text{ MB}}{119 \text{ MB/s}} \approx 17.2 \text{ 秒} 所需时间=119 MB/s2048 MB≈17.2 秒
当然,实际网络环境中很难一直跑满峰值,但这为我们提供了一个理论上的速度上限参考。
通过这个例子,我们要记住的核心点是:比特率描述的是物理层面上 0 和 1 的翻转速度,且其单位换算是基于 10 进制的。
三、波特率:串口通信的"心跳"
3.1 波特率 vs 比特率
网络上有些人会混用这两个词,但在严谨的通信技术中,它们是有区别的。
- 波特率 :单位是 Baud(波特),指每秒传输的符号(Symbol)或码元的数量。它反映的是信号变化的频率。
- 比特率:单位是 bps,指每秒传输的**二进制位(bit)**的数量。
3.1.1 "扔球游戏"通俗原理解析
为了搞清楚这两者的关系,我们可以想象张三和李四在玩扔球游戏。

假设他们约定用不同颜色的球来代表不同的信息状态:
- 蓝色球 =
00 - 绿色球 =
01 - 黄色球 =
10 - 红色球 =
11

在这个系统中,一个球就是一个"符号"(Symbol)。因为一共有 4 种颜色,区分这 4 种状态需要 2 个比特位( 2 2 = 4 2^2=4 22=4)。
- 如果张三每秒钟扔出 5 个球,那么波特率就是 5 Baud。
- 但是,因为每个球携带了 2 bit 的信息,所以比特率 就是 5 × 2 = 10 bps 5 \times 2 = 10 \text{ bps} 5×2=10 bps。
再举一个例子:

结论 :只有当每个符号只携带 1 bit 信息时(比如只有高电平和低电平两种状态),波特率在数值上才等于比特率。而在我们常见的标准 UART/USART 串口通信中,通常就是一个电平变化代表一个 bit,所以在这种特定场景下,我们可以近似认为 波特率 ≈ \approx ≈ 比特率。
注意:严格来说,"波特率"这个词中的"率"字其实是多余的,因为 Baud 本身就是速率单位。就像我们说"m/s"是速度,不会说"m/s率"一样。但由于历史习惯,已经习惯了叫"波特率",我们在技术交流中继续沿用即可。另外,千万不要把波特率简称为 BPS (Baud Per Second),这在学术上是不严谨的。
3.2 波特率在波形上的体现
回到我们的 MCU 串口通信。当我们设置波特率为 10 时,这意味着什么?


这意味着在 1 秒钟的时间内,信号线上会发生 10 次状态变化(或者说传输了 10 个码元)。
- 时间周期计算 : 1 s ÷ 10 = 0.1 s = 100 ms 1\text{s} \div 10 = 0.1\text{s} = 100\text{ms} 1s÷10=0.1s=100ms。
- 波形表现:每一个高低电平的持续时间就是 100ms。发送方发出一个高电平,必须稳稳地保持 100ms,然后才能翻转为低电平,再保持 100ms。
如果波特率提高到 115200,那么每个比特位的持续时间就缩短到了约 8.68 微秒( μ s \mu s μs)。这就对硬件的响应速度和抗干扰能力提出了更高的要求。
四、如何确立通信握手
4.1 历史遗留的标准数值
在 STM32 等 MCU 的 USART 外设配置中,你会发现波特率的可选值并不是随意的整数(如 1000、2000),而是诸如 9600、115200 这样看起来有些奇怪的数字。
这完全是历史原因导致的。早期的通信设备和电传打字机受限于机械结构和时钟分频的限制,形成了一套约定俗成的标准序列。虽然现在的电子技术完全可以支持任意速率,但为了保证兼容性,这些经典数值被保留了下来。
- 低速场景 :通常使用
9600Baud。适用于距离较远、干扰较大或对实时性要求不高的传感器通信。 - 高速场景 :通常使用
115200Baud。适用于调试打印(printf)、高速数据采集等场景。

4.2 解决通信失败的关键:约定一致
现在我们可以回答最开始提出的问题了:如何解决的通信不同步问题?
答案非常简单:双方必须约定完全一致的波特率。
MCU 内部的 USART 外设是由你写代码控制的,外部设备的参数也是由你选型决定的。你有绝对的权力去统一双方的标准。
- 正确做法 :将 MCU 的 USART 波特率配置为
115200,同时将串口设备(如 GPS 模块、蓝牙模块或电脑端的串口助手)也设置为115200。此时,双方对于"1秒钟传多少个 0 和 1"有了共同的认知,通信就能正常进行。 - 错误做法 :MCU 设为
115200,而接收端设为9600。这就好比一个人语速极快,另一个人语速极慢,接收端会把发送端的多个比特误读为一个,或者漏掉大量数据,最终导致通信彻底失败。
五、帧格式约定
在解决了通信速度的同步问题后,我们紧接着要面对第二个核心挑战:如何确保发送的数据是完整的?换句话说,接收方怎么知道数据什么时候开始、有多少位、以及什么时候发送完毕?这就引出了我们接下来要深入探讨的"帧格式"。

5.1 为什么必须约定"帧格式"?
在异步串行通信(如 USART)中,由于没有像 SPI 或 I2C 那样的独立时钟线(Clock Line)来同步双方的节奏,我们必须依赖一种人为约定的规则。这种规则在单片机领域通常被称为数据帧格式 ,其本质就是一种协议。
这个约定必须在设计硬件单元之前就已经确定下来。未来的硬件工程师在设计 USART 硬件电路时,必须严格遵照这个标准。只有当发送方和接收方都遵循同一套"语言规则"时,接收方才能正确解析出发送方发出的每一帧数据。
简单来说,波特率解决了"速度一致"的问题,而帧格式则解决了"内容解析"的问题。波特率决定了单位时间内能发送多少个数据帧,而帧格式决定了每个数据帧内部长什么样。
5.2 标准 USART 数据帧的解剖
一个标准的 USART 数据帧通常由以下几个部分组成,我们可以把它想象成寄信时的信封规范:


-
空闲状态 (Idle State)
- 电平状态:高电平(逻辑 '1')。
- 作用 :当没有数据传输时,通信线路默认保持高电平。这就像电话线没人说话时是静音的一样,是一个基准状态。

-
起始位 (Start Bit)
- 电平状态:低电平(逻辑 '0')。
- 持续时间:1 个位周期。
- 核心作用 :这是通信的"发令枪"。发送方将线路从高电平拉低,通知接收端"我要开始传数据了"。接收端检测到这个下降沿后,就会启动内部的定时器,按照约定的波特率开始采样后续的信号。这也帮助接收端完成了时钟的初步同步。

-
数据位 (Data Bits)
- 内容:实际传输的有效数据。
- 长度 :通常为 5 到 9 位,最常见的是 8 位(即一个字节)。
- 传输顺序 :LSB First(最低有效位优先) 。这意味着在二进制数中,最右边的那一位会最先被发送到线路上。例如要发送二进制
1011,线上的顺序会是1 -> 1 -> 0 -> 1。


5.2.1 传输顺序详解:LSB First 与 MSB First
上面数据位的相关细节再继续作补充:这 8 位(或 9 位)数据,到底是先发"头"还是先发"尾"?这就涉及到了 LSB 和 MSB 的概念。
什么是 LSB?
LSB 是 Least Significant Bit 的缩写,意为最低有效位。
- 定义 :在一个二进制数中,LSB 是位于最右边 的那个位,它具有最小的位权(即 2 0 2^0 20)。
- 示例解析 :
以二进制数1011为例,其数值计算方式为:
1 × 2 3 + 0 × 2 2 + 1 × 2 1 + 1 × 2 0 1 \times 2^3 + 0 \times 2^2 + 1 \times 2^1 + 1 \times 2^0 1×23+0×22+1×21+1×20
可以看到,最右边的那个 1 就是 LSB。 - 发送顺序 :如果要发送
1011,按照 LSB 优先的原则,物理线路上的发送顺序应该是 1 -> 1 -> 0 -> 1 。也就是先发送低有效位,再发送高有效位。
什么是 MSB?
MSB 是 Most Significant Bit 的缩写,意为最高有效位。
- 定义 :在一个二进制数中,MSB 是位于最左边的那个位,它具有最大的位权。
- 示例解析 :
同样以二进制数1011为例,最左边的那个 1 就是 MSB。 - 发送顺序 :如果要发送
1011,按照 MSB 优先的原则,物理线路上的发送顺序应该是 1 -> 0 -> 1 -> 1 。也就是先发送高有效位,再发送低有效位。
在 USART 中的实际应用
在绝大多数异步串行通信标准(如 USART 、RS-232 )中,数据通常默认采用 LSB First(低位先行) 的方式进行传输。
- 为什么要 LSB First?
这主要是为了让接收设备能够更快地开始处理数据。接收端不需要等待整个字节全部接收完毕就可以开始移位处理,这在早期的硬件设计中能提高效率。 - 例外情况 :
虽然 LSB First 是主流,但少数特定的通信协议或系统可能会配置为 MSB First 传输。不过,在标准的单片机 USART 开发中,我们遇到的绝大多数情况都是 LSB First。在编写代码或配置寄存器时,通常不需要刻意去改这个顺序,除非你有特殊的对接需求。。
-
校验位 (Parity Bit) ------ 可选
- 位置:位于数据位之后,停止位之前。
- 作用 :用于简单的错误检测。如果启用了校验,硬件会自动计算并添加这一位。
- 奇校验 (Odd Parity) :确保数据位 + 校验位中"1"的总个数为奇数。例如数据
11110000(4个1),校验位需置1,凑成5个1。 - 偶校验 (Even Parity) :确保数据位 + 校验位中"1"的总个数为偶数。例如数据
11110000(4个1),校验位需置0,保持4个1。
- 奇校验 (Odd Parity) :确保数据位 + 校验位中"1"的总个数为奇数。例如数据
- 注意:校验只能检测出奇数个比特翻转的错误,无法纠正错误,也无法检测出偶数个比特同时出错的情况。
-
停止位 (Stop Bit)
- 电平状态:高电平(逻辑 '1')。
- 持续时间:可配置为 1、1.5 或 2 个位周期。
- 核心作用 :标志着一帧数据的结束。它将线路拉回高电平(空闲状态),给接收端一个缓冲时间,并为下一帧的起始位(下降沿)做准备。如果没有停止位,接收端可能无法区分两帧数据之间的界限。


5.3 传输过程的量化计算
理解了帧结构,我们就能算一笔账:到底一秒钟能传多少有效数据?
这里有一个关键概念:发送 N 个字节的数据,就会产生 N 个独立的帧。每一帧都必须包含完整的起始位、数据位和停止位。不能把起始位和停止位省略掉。
让我们通过两个经典波特率来计算一下实际传输速率(假设配置为:1位起始位 + 8位数据位 + 无校验 + 1位停止位 = 10位/帧):
-
场景一:波特率 9600 bps
- 每秒传输的总位数:9600 bits
- 每帧占用位数:10 bits
- 理论每秒传输字节数 : 9600 ÷ 10 = 960 9600 \div 10 = 960 9600÷10=960 字节/秒。
-
场景二:波特率 115200 bps
- 每秒传输的总位数:115200 bits
- 每帧占用位数:10 bits
- 理论每秒传输字节数 : 115200 ÷ 10 = 11520 115200 \div 10 = 11520 115200÷10=11520 字节/秒。
通过这个计算我们可以直观地看到,波特率越高,单位时间内传送的数据量(吞吐量)就越大。但也要注意,起始位和停止位占据了 20% 的带宽(2/10),这就是异步通信为了"握手"所付出的额外开销。
结语
