USART 串口基础理论:从原理到 STM32 外设架构
各位同学,咱们今天来聊聊串口。说实话,串口通信是我入行嵌入式接触的第一个通信协议,也是我到现在为止用得最多的协议——没有之一。你想想看,从调试打印到蓝牙模块通信,从 GPS 数据读取到和 Wi-Fi 模块握手,哪样离得开串口?
这一章咱们把串口的基础理论彻底吃透。别觉得理论枯燥,我跟你讲,很多项目出问题,根子就在这些基础概念上没搞明白。
串口通信原理:数据是怎么“飞”过去的?
串口通信,全称是串行通信接口。说白了,就是一根线发数据,一根线收数据,数据一个比特一个比特地排着队走。
我刚开始学的时候有个疑问:为什么不用并行通信?一次传 8 位多快啊。后来在项目里吃过亏才明白——并行通信线多、干扰大、距离短。串口虽然“慢”,但简单可靠,两根线就能搞定。
核心要点:串口通信的本质是“串行化”——把并行数据转成时间序列上的比特流,通过一根数据线逐位发送。
串口通信的基本过程是这样的:
- 空闲状态:数据线保持高电平
- 起始位:拉低电平,告诉接收方“我要开始发了”
- 数据位:从低位到高位,逐位发送数据
- 校验位(可选):检查数据有没有传错
- 停止位:拉高电平,表示这一帧结束
嗯,这里要注意:串口通信是帧结构驱动的。每一帧就是一个完整的数据包,接收方靠起始位和停止位来“对齐”数据。
同步 vs 异步:时钟信号去哪儿了?
这个问题我当年面试的时候被问过,后来带新人时也经常考他们。
同步通信:发送方和接收方共用一根时钟线。时钟来了,双方同时动作。就像军训喊“一二一”,步调完全一致。I²C、SPI 都是同步通信。
异步通信:没有专门的时钟线。双方各自用自己的时钟,靠约定的波特率来“猜”什么时候该采样。串口(UART/USART)就是典型的异步通信。
| 对比项 | 同步通信 | 异步通信 |
|---|---|---|
| 时钟线 | 需要 | 不需要 |
| 传输速率 | 高(可到几十 MHz) | 较低(通常 115200 bps 以内) |
| 硬件复杂度 | 高(多一根时钟线) | 低(两根线搞定) |
| 抗干扰能力 | 较强 | 较弱(依赖时钟精度) |
| 典型应用 | SPI、I²C | UART、RS-232、RS-485 |
我的经验:做蓝牙模块驱动时,我习惯用异步串口。因为蓝牙模块本身就有自己的时钟,不需要 MCU 额外提供时钟线,省一根线就是省一个 GPIO,这在 PCB 布局紧张时特别重要。
波特率:通信的“节拍器”
波特率,单位是 bps(bits per second),表示每秒传输多少个比特。115200 bps 就是每秒传 115200 个比特。
你可能会问:波特率和比特率有什么区别?
在串口通信中,一个符号(symbol)就是一个比特,所以波特率 = 比特率。但在更复杂的调制方式中,一个符号可能携带多个比特,那时候两者就不相等了。不过咱们做串口,直接当一回事就行。
常见的波特率有:9600、19200、38400、57600、115200。我个人习惯用 115200,因为速度够快,而且大部分模块都支持。
避坑指南:我曾经在一个项目里,发送端设 115200,接收端设 9600,结果数据全是乱码。查了半天才发现是波特率没对上。记住:通信双方波特率必须完全一致,误差不能超过 ±2%。
数据位、停止位、校验位:帧结构的“三要素”
咱们来拆解一帧串口数据:
数据位:通常是 8 位(一个字节),也可以是 5、6、7 位。我建议一律用 8 位,因为一个字节正好 8 位,处理起来最方便。
停止位:可以是 1 位、1.5 位或 2 位。停止位越长,帧间隔越大,可靠性越高,但速度越慢。我一般用 1 位停止位,够用了。
校验位:有三种模式——
- 无校验(None):不校验,最常用
- 奇校验(Odd):数据位 + 校验位中 1 的个数为奇数
- 偶校验(Even):数据位 + 校验位中 1 的个数为偶数
举个例子:数据位是 0b10101010(四个 1),如果用偶校验,校验位就是 0(保持偶数个 1);如果用奇校验,校验位就是 1(凑成奇数个 1)。
我的建议:和蓝牙模块通信时,我通常用 8 位数据位、1 位停止位、无校验。因为蓝牙模块内部已经做了 CRC 校验,串口层再加校验意义不大,反而降低效率。
STM32F407 USART 外设架构
好,理论讲完了,咱们来看看 STM32F407 的 USART 外设长什么样。
F407 有 6 个串口:USART1~USART3 和 UART4~UART6。其中 USART1 挂载在 APB2 总线上(最高 84 MHz),其余都在 APB1 上(最高 42 MHz)。
USART 的内部架构,我画了一张图:
USART 的核心寄存器就三个:
- USART_DR:数据寄存器,读写都走它
- USART_SR:状态寄存器,看 TXE(发送空)、RXNE(接收非空)等标志位
- USART_BRR:波特率寄存器,设置通信速率
配置流程其实很简单:
- 使能 USART 时钟和 GPIO 时钟
- 配置 TX/RX 引脚为复用功能
- 设置波特率、数据位、停止位、校验位
- 使能 USART
- 发送时写 DR,接收时读 DR
小技巧:我习惯在初始化时先使能 USART 的接收中断(RXNEIE),这样数据来了自动进中断,不用轮询。轮询虽然简单,但在高负载系统里会浪费 CPU 时间。
USART vs UART:多了一个“S”有什么区别?
这个问题经常有人问。USART 多了一个 S(Synchronous),意思是它同时支持同步和异步模式。而 UART 只支持异步。
在同步模式下,USART 可以输出时钟信号(SCLK 引脚),用于和外部设备同步。但说实话,我在实际项目中几乎没用过 USART 的同步模式——需要同步通信时我直接上 SPI 了。
所以,你完全可以把 STM32F407 的 USART 当 UART 用,只关注异步模式就行。