## 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 --- _每主题一页,复习时只翻本目录。_