36.I2C-vs-SPI-vs-UART.md 8.0 KB

I2C vs SPI vs UART

判别规则(核心,唯一要记的)

  1. 选型看"挂多少 + 快不快 + 干什么":挂一堆低速小器件、要省线 → I2C;大块数据要快(Flash/屏)→ SPI;两个设备对连/调试 → UART
  2. 有时钟线 = 同步(I2C/SPI),没时钟线 = 异步(UART,靠波特率对表)
  3. SPI 全双工最少 4 根线(只读场景可省 MISO 到 3 根);I2C 靠地址 + ACK、SPI 靠 CS 片选、UART 靠波特率配对

一句话:"挂一堆慢器件省线用 I2C,大块快数据用 SPI,两设备对连用 UART;有时钟=同步,没时钟=异步。"

双工(先懂这个)

"双工" = 数据能不能同时两个方向走:

名称 同一时刻 像什么 谁是这样
单工 只能一个方向 收音机广播 少见
半双工 只能一个方向,但可换方向 对讲机 I2C
全双工 两个方向同时 打电话 SPI、UART
  • I2C 半双工:只有一根 SDA 数据线,主机发的时候从机没法同时回,发完才能换方向
  • SPI 全双工:MOSI + MISO 两根独立线,一个时钟换一位、两边同时
  • UART 全双工:TX + RX 两根独立线,各走各的

抽象描述(一句话本质)

三种都是"芯片之间传数据"。区别在三个硬指标:几根线、有没有时钟线(同步/异步)、每秒能传多少位


I2C:2 根线,同步,慢,一总线挂多设备

物理

  • SDA(数据)+ SCL(时钟),两根
  • 开漏输出 + 外部上拉:只能"拉低"或"释放"(释放被电阻拉高),空闲两线都是高

数据怎么交换(逐步)

① 起始:SCL 高时 SDA 由高→低 → 告诉所有从机"要开始了"
② 寻址:SCL 打 8 个时钟,SDA 送出 7 位地址 + 1 位读写位
③ ACK:匹配的从机拉低 SDA 一个时钟 → "我在"
④ 数据:按"8 位数据 + 1 位 ACK"重复
⑤ 停止:SCL 高时 SDA 由低→高 → 传输结束

数据位规则:SCL 高时 SDA 必须稳定(接收方在高电平采样),SCL 低时才允许变化。

特点

  • 半双工、慢(每字节 9 时钟 + 起止开销;100K~400K bit/s)
  • 靠地址找设备,一根总线挂几十上百个从机
  • 省线(2 根),引脚紧张首选

SPI:4 根线,同步,快,主从靠片选

物理

  • SCLK(时钟)+ MOSI(主出从入)+ MISO(主入从出)+ CS(片选,低有效)
  • 每从机单独一根 CS,其余三根共享

数据怎么交换(逐步)

① 主机把某从机的 CS 拉低 → 该从机上线,其余 CS 高不参与
② 主机打时钟,双方各一个移位寄存器,被 MOSI/MISO 连成环:
   每个时钟边沿,主机从 MOSI 移出 1 位,同时从 MISO 收回 1 位
   8 个时钟 = 换 1 字节(两方向同时)
③ 传完,CS 拉高 → 从机下线

特点

  • 全双工:一个时钟同时双向换一位
  • 快:无地址、无 ACK、无起止条件,每字节就 8 个时钟;SCLK 可达几十 MHz
  • 无地址、无应答:发出去不知道从机收到没(协议层自己加)——换来速度
  • CPOL/CPHA(时钟极性和相位)主从必须对上,否则错位
  • 线多(每从机一根 CS),但带宽大

UART:2 根线,异步,靠波特率对表,点对点

物理

  • TX + RX 两根,A 的 TX 接 B 的 RX(交叉),共地
  • 没有时钟线——和 I2C/SPI 的本质区别

数据怎么交换(逐步)

① 空闲 TX 为高
② 起始位:TX 拉低 1 位时间 → 接收方靠下降沿对齐开始
③ 数据位:依次 8 位(低位在前),每 1 位占 1 个位时间
④ 停止位:TX 拉高 1 位时间 → 一帧结束
帧 = 起始位(1) + 数据位(8) + 停止位(1)(可加校验位)

没时钟怎么对(三个机制)

  1. 约定波特率:双方各自用自己的时钟,约定"每秒传多少位"(如 115200)
  2. 起始位对齐:检测到 TX 高→低的下降沿 = 开始,从此对齐
  3. 中点采样:按波特率计时,在每个位的正中间采样(不在边沿),时钟误差 ±3% 内能扛住

特点

  • 全双工、无主从(点对点平等)
  • 速度中(9600 / 115200 常见,高速几 Mbps)
  • 没时钟兜底 → 高速长线易受干扰丢帧,不适合大块高速数据

为什么 I2C 慢、SPI 快(机制三连)

I2C 慢

  1. 每字节开销大:8 数据 + 1 ACK = 9 时钟,还有起始/寻址/停止
  2. 开漏 + 上拉:只能拉低,拉高靠电阻慢充 → 频率上不去
  3. 半双工:同一根线,发完才能收

SPI 快

  1. 开销极小:无地址/ACK/起止,每字节就 8 时钟纯数据
  2. 推挽驱动:既能主动拉高又能拉低,边沿陡翻转快 → 几十 MHz
  3. 全双工:一个时钟换一位,效率翻倍

为什么 UART 没时钟线还能传(总结)

约定波特率 + 起始位下降沿对齐 + 每位中点采样,三个机制兜底,没时钟线也能准确收发。

为什么大块高速数据选 SPI 不选 UART

  1. 波特率上限低:常见 115200,高速几 Mbps;SPI 几十 MHz
  2. 异步没时钟兜底:速度一高、线一长就时钟误差 + 干扰 → 丢帧错位
  3. 每字节有额外开销:起始 + 停止 ≈ 10~11 位/字节,浪费带宽

硬数据对比表(背这张)

指标 I2C SPI UART
线数 2(SDA+SCL) 4(MOSI/MISO/SCLK/CS,每从机多 1 CS) 2(TX/RX)
同步/异步 同步 同步 异步
双工 半双工 全双工 全双工
找对家 7 位地址 + ACK CS 片选(无地址) 无寻址,直接连
速度量级 K 级(100K~1M) MHz 级(几十 M) K~M 级波特率
典型器件 传感器/EEPROM/OLED Flash/显示屏/SD 卡 调试口/GPS/蓝牙模块

正反例(建立直觉)

  • 正例1:5 个传感器 + 引脚紧张 → I2C(2 根线 + 地址,省线)
  • 正例2:2MB 数据快速烧写外部 Flash → SPI(MHz 级)
  • 正例3:GPS 模块接单片机 → UART(两设备对连)
  • 反例1:高速显示屏用 I2C → 太慢,带宽不够(I2C 是 K 级)
  • 反例2:SPI 从机既要收配置又要回状态 → 必须 4 根线(全双工),别省 MISO
  • 反例3:以为 UART 有主从 → 没有,点对点平等

变体验证(3 题,全过=学会)

  1. 5 个传感器 + 引脚紧张 → I2C(2 根线共享总线 + 地址寻址,省线)
  2. 陷阱题:"SPI 最少 3 根线" → 不完整。全双工最少 4 根(MOSI+MISO+SCLK+CS);只读场景才可 3 根(省 MISO)。面试答"全双工 4 根、只读 3 根"
  3. 快速烧 2MB 到外部 Flash → 不能用 I2C(K 级太慢),用 SPI(MHz 级)

口述要点(面试怎么讲)

  • 结论先行:挂多/省线 → I2C;大块快 → SPI;对连调试 → UART
  • 双工:I2C 半双工(一根数据线换向),SPI/UART 全双工(两根独立线同时)
  • I2C 为什么慢:每字节 9 时钟 + 寻址 ACK 开销 + 开漏上拉拉高慢 + 半双工
  • SPI 为什么快:纯数据无开销 + 推挽陡边沿 + 全双工
  • UART 没时钟怎么传:约定波特率 + 起始位下降沿对齐 + 中点采样(误差 ±3% 内扛得住)
  • 大块高速为何不用 UART:波特率上限低 + 异步无时钟兜底易丢帧 + 每字节多起始停止位
  • 易错点:SPI 最少几根线只答 3 根;把 UART 当有主从;搞混同步/异步(有无时钟线)

关系网络

相邻概念 关系 孤立理解会犯的错
时钟树 串口/SPI 的波特率/时钟都由 RCC 提供 波特率算错不知查时钟源
DMA 串口/SPI 大批量收发用 DMA 提高效率 不知 DMA 能配到串口/SPI
中断 UART 不定长接收用中断方式 全用轮询阻塞主循环
HAL vs LL HAL 三种模式(轮询/中断/DMA)配合这三协议 选错模式

学习日期

2026-08-18


每主题一页,复习时只翻本目录。