STM32 通信接口:SPI、I²C、USART原理
CPHA=0:在前沿(Leading edge)采样,CPHA=1:在后沿(Trailing edge)采样。(4)NSS/CS(Chip Select):片选,通常低有效,定义一次事务的边界。(stream),没有像 I²C 的 START/STOP、SPI 的 NSS 那样的“事务边界”,所以可靠通信通常要上层协议(包头/长度/CRC/超时等)。注:这里的“前沿/后沿”含义:若 CPOL=0(
目录
1. 引言
在 STM32 项目里,通信接口几乎决定了系统的“数据通路上限”和“稳定性下限”。很多问题并不是协议本身复杂,而是工程上忽略了关键约束:电气驱动方式、帧边界、错误恢复、以及与中断/DMA 的协同。
2. I²C:两根线的多主机同步总线(SCL/SDA)


I2C总线是由Philips公司开发的一种双向二线制同步串行总线。I²C的 数据线(SDA)/时钟线(SCL)不是推挽(PP, Push-Pull),而是开漏(OD, Open-Drain)+上拉电阻的方式。只能输出两种状态:拉低(0):用内部 MOS 管把线拉到 GND。放开(1):高阻态,自己不驱动高电平。线上的高电平由外部 上拉电阻 RPU 拉到 VDD。当任何一个节点拉低时,线上就一定是 0;当所有节点都放开,线上才是 1,即:任一设备拉低 → 总线为 0所有设备放开 → 上拉电阻拉高 → 总线为 1。
I通过开漏(OD, Open-Drain)+上拉电阻这种输出方式可以实现这几项功能:(1)多设备共享同一根线且不会打架。任何设备只能拉低或放开(高阻),不会出现推挽那种“一个强拉高、另一个强拉低”的硬冲突。(2)多主机仲裁(Multi-master arbitration)可行。主机发送“1”时实际上是放开线路,同时读回 SDA;如果读到 0 就说明别的主机在拉低,它自动退出。此机制只有开漏的“线与”逻辑才安全成立。(3)时钟拉伸(Clock Stretching):从机可把 SCL 拉低让主机等待(推挽会打架)
注:高电平由上拉电阻通过 RC 充电形成,上升沿速度取决于总线电容和上拉阻值,因此 I²C 对线长、挂载数量、速率非常敏感。
2.1 START/STOP边界
I²C 的“帧边界”不是靠长度,也不是靠空闲时间,而是靠电平条件:
START:SCL 为高时,SDA 从高变低(1→0)。
STOP:SCL 为高时,SDA 从低变高(0→1)。
2.2 数据有效规则
I²C 的基本约束是:SCL 高电平期间 ,SDA 必须稳定。SCL 低电平期间,允许 SDA 改变(准备下一位);SCL 高电平期间,SDA 必须保持不变(采样窗口)。如果判定“时序是否可靠”,可以采用:(1)SDA 的跳变是否主要发生在 SCL 低电平;(2)在 SCL 高电平段,SDA 是否出现毛刺/缓慢爬升导致误采样。
## 2.3 ACK/NACK
每 8 位后第 9 位确认ACK/NACK。I²C 以字节为单位传输:8bit 数据 + 1bit ACK(第 9 个时钟)。ACK(0):接收方在第 9 位把 SDA 拉低NACK(1):接收方不拉低(放开),表示不接受/结束。
在工程中,写操作时:从机对地址/数据逐字节 ACK,表示“收到了”。读操作时:主机对从机返回的每个字节 ACK(继续读)或 NACK(读完了)。
2.4 协议层:地址、读写方向、Repeated START(典型寄存器访问)
(a)地址与方向位(7-bit addr + R/W)
第一个字节通常是:[7-bit Address] + [R/W],R/W=0:写(主机写到从机);R/W=1:读(主机 从 从机 读)。R/W=1:读(Master 从 Slave 读)。
(b)寄存器读(Write reg addr → Repeated START → Read)
典型传感器/EEPROM“读某寄存器”的流程:1.START;2.发送 ADDR + W,从机 ACK;3.发送 REG(寄存器地址),从机 ACK;4.Repeated START(不发 STOP,直接再发 START);5.发送 ADDR + R,从机 ACK;6.从机回 DATA,主机对最后一个字节 NACK(表示结束);7.STOP。
2.5 速度与波形

I²C 的速度与波形容易出现“能通但不稳”的现象。原因是因为 I²C 高电平是上拉电阻拉出来的,不是推挽强驱动,所以 SDA/SCL 上升沿是 RC 充电:
V t = V D D ⋅ ( 1 − e − t R P U C B U S ) {V_{t}}=VDD\cdot (1-e^{-\frac{t}{R_{PU}C_{BUS} } } ) Vt=VDD⋅(1−e−RPUCBUSt) 通过公式可以看出:(1)总线电容 CBUS 越大(线更长、器件更多、ESD/引脚电容更大)→ 上升沿越慢;(2)上拉电阻 RPU 越大 → 上升沿越慢;(3)上升沿慢会导致:400kHz/1MHz 下高电平达不到有效门限就被采样ACK/NACK 判定不稳定看起来“偶发 NACK、偶发读错、偶发挂死”。
因此 I²C 设计里,上拉电阻不是可有可无,而是速率与稳定性的关键参数。
3. SPI:高速、全双工、点对点(或多从机)的同步总线
SPI(Serial Peripheral Interface)是同步串行接口,典型为单主多从架构。同步的关键是:主机产生时钟 SCK,所有数据采样都绑定在 SCK 的边沿上,因此 SPI 在短距离板级通信里可以做到很高的吞吐和很强的确定性。SPI 典型信号线有:(1)SCK(Serial Clock):主机输出时钟。(2)MOSI(Master Out Slave In):主机→从机。(3)MISO(Master In Slave Out):从机→主机数据数据。(4)NSS/CS(Chip Select):片选,通常低有效,定义一次事务的边界。下图为SPI原理图与时序图。

3.1 SPI本质
SPI 外设内部通常就是两组移位寄存器(Shift Register)在工作:
主机发送:把要发的字节装入 TX 移位寄存器。
SCK 每跳一次,就移出 1bit 到 MOSI。
同时从机也在移出 1bit 到 MISO(如果从机已准备好要回的数据)。
因此 SPI 最典型特性是:全双工(Full-Duplex)。一边发数据(MOSI),一边收数据(MISO),每个时钟周期完成 1bit 的交换。
3.2 关键约束
SPI 的采样规则由两个参数决定:CPOL(Clock Polarity)和CPHA(Clock Phase)。
CPOL:SCK 空闲电平。CPOL=0:空闲低电平,CPOL=1:空闲高电平;CPHA(Clock Phase):数据在“前沿”采样还是“后沿”采样。CPHA=0:在前沿(Leading edge)采样,CPHA=1:在后沿(Trailing edge)采样。
注:这里的“前沿/后沿”含义:若 CPOL=0(空闲低),前沿=上升沿,后沿=下降沿;若 CPOL=1(空闲高),前沿=下降沿,后沿=上升沿。
3.3 四种模式
SPI主要有四种模式,如下表。
| Mode | CPOL | CPHA | SCK 空闲 | 前沿 Leading | 后沿 Trailing | 采样边沿 |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 低 | 上升沿 | 下降沿 | 上升沿采样 |
| 1 | 0 | 1 | 低 | 上升沿 | 下降沿 | 下降沿采样 |
| 2 | 1 | 0 | 高 | 下降沿 | 上升沿 | 下降沿采样 |
| 3 | 1 | 1 | 高 | 下降沿 | 上升沿 | 上升沿采样 |
四种模式对应的波形图如下:
从波形“快速判定 CPOL/CPHA 是否匹配”
1.先看空闲电平(NSS=高时的 SCK)→ 定 CPOL。
- 空闲 SCK=0 → CPOL=0
- 空闲 SCK=1 → CPOL=1
2.再看 MOSI 在哪个边沿附近跳变 → 定 CPHA 是否反了。
- 正确配置:采样边沿到来时,数据应已稳定;数据跳变应出现在另一个边沿附近
- 若你看到“数据总在采样边沿附近翻转”,那基本就是 CPHA 错
CPHA 错最典型现象:数据整体错位 1 bit(bit-slip)读出来像“每个字节都偏一位”,像 0xAA/0x55 特别明显。
3.4 NSS/CS 的工程含义
SPI 没有像 I²C 那样的 START/STOP,因此工程上通常把一次通信定义为:
(1)NSS 拉低:事务开始,从机被选中。
(2)NSS 拉高:事务结束,从机释放 MISO,并(很多器件)内部状态机复位/结束本次命令。
对 SPI Flash、屏幕、ADC/DAC 等器件而言,NSS 的边界经常直接决定:
(1)命令帧是否被识别。
(2)连续读写是否被正确“拼接”。
(3)是否会进入/退出某个内部状态。
4. UART:异步串口
UART 是无共享时钟的“异步串行帧”,其本质是:双方不共享时钟线,只约定一个“位时间”(bit time),也就是波特率 baud。发送端按这个节拍把位流吐到 TX;接收端用自己的本地时钟去采样 RX 并恢复位流。
在工程上,UART 简单通用、跨平台强,但它天然是 字节流(stream),没有像 I²C 的 START/STOP、SPI 的 NSS 那样的“事务边界”,所以可靠通信通常要上层协议(包头/长度/CRC/超时等)。 下图为UART的原理图。

4.1 帧结构(Framing)
UART常见的为8N1帧格式,见下图。
8N1 的含义:8:数据位 8bit;N:无校验位(No parity);1:1 个停止位。
4.2 异步采样
异步采样的核心为中点采样 + 过采样(Oversampling)。
接收端怎么知道何时采样?
接收端通常这样做:
(1)在空闲高电平时持续监测 RX。
(2)检测到下降沿(疑似 Start 位开始)。
(3)等待半个 bit time,去采样 Start 位的“中点”确认它确实为 0。
(4)之后每隔 1 个 bit time,在每个数据位“中点附近”采样一次,依次得到 D0…D7.
(5)最后采样 Stop 位应为 1,否则就是帧错误。
注:“采样在中点”的意义:避开边沿抖动、噪声、以及发送端/接收端时钟的相位误差。
为什么要 16×/8×过采样?
以 STM32 USART 为例,接收端通常采用 16×(或 8×)过采样:
(1)本地时钟先被分频成过采样时钟(比如 16×baud)。
(2)通过多次采样与投票/滤波,提高抗噪声能力。
(3)同时也让“中点采样位置”可更精细地调整(数字锁相/重同步)。
4.3 与 RS485 的关系
UART 是帧/字节层,RS485 是电气/物理层。工程是 USART1 + RS485 + DE/RE时,这里需要明确分层:
(1)UART/USART:负责把字节封装成“异步帧”(Start/Data/Stop),并收发字节。
(2)RS485 收发器:负责把单端 TTL 电平转换为差分 A/B,增强远距离与抗干扰。
(3)DE/RE:控制半双工方向。发送:DE=1 使能驱动,通常关闭接收(/RE=1)避免回显污染。接收:DE=0,/RE=0。
注:发送结束回切接收必须等待 USART 的 TC=1(最后一个停止位真正发完),否则会截断尾部造成对端 CRC/帧错误。
4.4 波特率误差与“能收不稳”的根因
为什么 UART 对波特率误差敏感?
因为没有共享时钟,发送端与接收端的“位时间”必须足够接近。接收端虽然在 Start 位对齐了一次,但在一帧内部仍会累积相位误差。
直观理解:
(1)如果接收端采样点逐渐漂移到位边界附近,就可能把相邻位采错。
(2)数据位越多、停止位越短、波特率越高,对误差越敏感。
工程上常见导致误差/不稳的因素:
(1)HSI 精度差(温漂/误差大)。
(2)时钟树配置导致 BRR 误差。
(3)长线/干扰导致边沿畸变(看似波特率对但采样不稳)。
UART 的典型错误类型(STM32 常见)
(1)FE(Framing Error)帧错误:Stop 位不为 1(常见于波特率不匹配/干扰)。
(2)NE(Noise Error)噪声错误:采样窗口检测到噪声。 (3)PE(Parity Error)奇偶校验错误:启用校验时校验不匹配。
(4)ORE(Overrun Error)溢出:数据来得太快,你没及时读 DR/RDR。
5 SPI、I²C、USART对比
表1.核心特性与协议层对比
| 维度 | SPI | I²C | USART(UART) |
|---|---|---|---|
| 总线类型 | 同步串行(Synchronous Serial) | 同步串行(Synchronous Serial) | 异步串行(Asynchronous Serial) |
| 典型线数 | 4 线:SCK/MOSI/MISO/NSS(也可 3 线半双工) | 2 线:SCL/SDA | 2 线:TX/RX(可加 RTS/CTS) |
| 时钟来源 | 主机提供 SCK | 主机提供 SCL(可 Clock Stretching) | 无共享时钟(靠波特率同步) |
| 多主机支持 | 不标准化,多主机少用 | 标准支持 Multi-master + 仲裁 | 不支持总线级多主机(点对点为主) |
| 多从机支持 | 支持(通常每从机独立 NSS) | 支持(地址寻址) | 原生不支持(需要上层协议或 RS485 总线) |
| 地址机制 | 无(靠 NSS 选择从机) | 有(7-bit/10-bit 地址) | 无(字节流,需要上层帧/地址) |
| 双工能力 | 全双工(最常见)/半双工 | 半双工(同一 SDA 线读写分时) | 全双工(TX/RX 独立) |
| 数据单位 | 连续比特流(按字节/字对齐由配置决定) | 字节为基本单位(8 bit + ACK) | 字节流(帧格式约束在物理层) |
| 位序 | MSB/LSB 可配(多为 MSB first) | MSB first(常见实现) | LSB first(UART 传统) |
| 帧边界 | NSS 定义事务边界(最可靠) | START/STOP 定义事务边界 | 无固有帧边界(需上层协议:包头/长度/超时) |
| 硬件确认/应答 | 无内建 ACK(可用 MISO 返回状态) | 有 ACK/NACK(硬件级) | 无 ACK(依赖上层重传/校验) |
| 错误检测 | 无强制(可上层 CRC/校验) | 有 ACK 但无强制 CRC(可上层 CRC) | 可选校验位(Parity),更常用上层 CRC |
| 典型速率范围 | 高:数 MHz 到几十 MHz(与 MCU/外设/走线相关) | 中:100 k / 400 k / 1 M(Fm+)等 | 中:9.6 k ~ 数 Mbps(取决于双方与误差) |
| 延迟特性 | 低延迟、确定性强 | 中等(有 ACK、可能 Stretching) | 受波特率与帧解析影响,延迟不确定性更高 |
| 总线负载能力 | 更像点对点/星形(不适合长总线多点) | 多点共享更友好(但受电容限制) | 点对点;若做总线常配 RS485 |
| 线路电平/驱动 | 推挽为主(高速) | 开漏 + 上拉(wired-AND) | 推挽(TTL)/需转换到 RS232/RS485 |
| 典型应用 | SPI Flash、显示屏、ADC/DAC、RF/IMU 高速数据 | 传感器/配置寄存器、EEPROM、PMIC、RTC | 调试口、模块通信、GNSS、蓝牙/WiFi 模块 AT、工业串口 |
| 最典型优点 | 高速、简单、吞吐高、事务边界清晰 | 省线、多从机、硬件 ACK、总线共享 | 成本低、易调试、跨平台通用、可远距离配合收发器 |
| 最典型缺点 | 线多、无地址、NSS 管理复杂、多从机布线成本高 | 速率较低、上拉/电容敏感、易挂死需恢复 | 无帧边界、可靠性靠上层、误差/噪声导致丢字节 |
表2.工程实现与可靠性对比
| 维度 | SPI | I²C | USART(UART) |
|---|---|---|---|
| GPIO 电气配置 | SCK/MOSI:AF 推挽;MISO:输入;NSS 常用 GPIO 推挽 | SCL/SDA:AF 开漏 + 上拉(外部电阻) | TX:AF 推挽;RX:输入(常上拉) |
| 外设关键参数 | CPOL/CPHA、分频、位宽 8/16、NSS 管理、FirstBit | 速率、地址模式、ACK 使能、Stretching、滤波/上拉 | 波特率、字长、停止位、校验、过采样 |
| “能通但不稳”的主要根因 | 模式不匹配、SCK 太快、NSS 边界错误、信号完整性差 | 上拉不合适、总线电容大、从机异常导致 SDA 拉低、地址/ACK 问题 | 帧解析不健壮、RX 溢出 ORE、波特率误差、噪声导致 FE/NE |
| 事务边界/帧同步 | 强(NSS) | 强(START/STOP) | 弱(需 Idle/超时/长度字段) |
| 中断/DMA 适配 | DMA 非常适合(高吞吐) | DMA 可用但要处理事务/STOP/错误 | DMA+IDLE 最佳实践(高吞吐与帧检测) |
| 常用接收架构 | DMA 收一块 + NSS 边界;或 IRQ 按字节 | IRQ 状态机(EV/ER);DMA 用于块传输 | IRQ 环形缓冲(低速)/ DMA Circular + IDLE(高速稳) |
| 错误/异常处理复杂度 | 中(多为协议层自管) | 高(BUSY、ARLO、BERR、AF、总线恢复) | 中(ORE/FE/NE/PE,靠驱动+上层协议) |
| 总线恢复机制 | 一般不需要(除非从机锁死 MISO 等特殊) | 常需要:SCL 手动脉冲 + 重新初始化 | 依赖上层:重同步(找包头)、超时丢包、重传 |
| 线路长度与抗干扰 | 高速短线优先;长线需降速/端接/屏蔽 | 对电容极敏感;长线困难(需降速/缓冲器) | TTL 短线;加 RS485/RS232 可远距离强抗扰 |
| EMI/信号完整性 | 高速下要求高(串阻、回流路径、走线阻抗) | 上升沿由 R*C 决定,速率越高越敏感 | 速率越高越敏感;差分(RS485)显著改善 |
| 硬件成本(引脚/器件) | 引脚多;多从机需要更多 NSS 引脚 | 引脚最省(2 根线) | 引脚少(2 根线)但若远距需收发器 |
| 调试便利性 | 中(逻分/示波器最好) | 中偏难(总线挂死时需波形分析) | 高(串口助手/日志极方便) |
| 典型可靠性策略 | 降速→确认模式→再提速;NSS 用 GPIO;必要时加 CRC | 合理上拉、控总线电容、超时+恢复;异常复位策略 | 帧协议(SOF/Len/CRC)、超时、重传;DMA+IDLE |
| 适合承载“协议栈” | 可(自定义帧/CRC),但缺少地址 | 很适合寄存器型/短包 | 非常适合自定义协议(但必须定义边界) |
| 实时性/确定性 | 高(时钟可控、边界明确) | 中(可能 Stretching) | 中到低(受解析与缓冲影响) |
| 常见上层协议搭配 | Flash 指令集、显示驱动、传感器 burst | 传感器寄存器、EEPROM、PMBus/SMBus 类 | Modbus RTU、NMEA、AT、私有帧协议 |
更多推荐



所有评论(0)