SPI 通信:4 线盲操作 vs 5 线带忙信号,差一根线差多远
一句话: 标准 SPI 是 4 根线(CS+SCK+MOSI+MISO),MCU 只能凭经验延时等外设完成。多一根 BUSY 线变成 5 线——外设干完活了主动拉低 BUSY 通知 MCU,不用瞎猜"到时间了没"。
适合谁读:适合嵌入式开发者、单片机初学者及遇到类似问题的工程师
4 线 SPI:盲操作
MCU 外设芯片 CS ───────────────────────> CS SCK ──────────────────────> SCK MOSI ─────────────────────> MOSI MISO <───────────────────── MISO MCU 发完命令 → delay(100μs) → 盲猜"应该算完了" → 读数据问题:不知道外设到底算完了没有。延时设短了数据没准备好,设长了浪费时间。
5 线 SPI:多一根 BUSY
MCU 外设芯片 CS ───────────────────────> CS SCK ──────────────────────> SCK MOSI ─────────────────────> MOSI MISO <───────────────────── MISO BUSY <───────────────────── BUSY ← 多这一根MCU 发完命令 → 等 BUSY 变低 → 外设通知"我好了" → 立刻读数据不用猜时间,硬件通知。BUSY 从高变低的瞬间,数据一定准备好了。
什么芯片需要 BUSY 线
| 芯片类型 | 为什么需要 |
|---|---|
| 高精度 ADC | 转换需要时间(1.6μs~几十μs),转换中读数据 = 垃圾值 |
| 多通道序列器 ADC | 连续扫 8 路,每路转换完 BUSY 会有一个脉冲 |
| Flash 芯片 | 擦除/写入需要 ms 级别的时间 |
| 带校准的 DAC | 内部校准需要时间 |
代码对比
// 4线模式 — 靠延时硬等 void ADC_Read_4Wire(void) { CS_Low(); SPI_Write(CMD_CONVERT); // 发转换命令 CS_High(); Delay_Us(2); // 盲等 2μs(数据手册说 1.6μs 够了) CS_Low(); uint16_t data = SPI_Read(); CS_High(); } // 5线模式 — 靠 BUSY 信号 void ADC_Read_5Wire(void) { CS_Low(); SPI_Write(CMD_CONVERT); // 发转换命令 CS_High(); while (BUSY_Pin == HIGH); // 等硬件通知,不用猜时间 CS_Low(); uint16_t data = SPI_Read(); CS_High(); }ADC 的三种时序参数
| 参数 | 含义 | 最小值 | 代码怎么做 |
|---|---|---|---|
| RDC(转换时间) | CS 拉高后 ADC 算完需要多久 | 1.6 μs | CS 高后等 ≥1.6μs |
| RAC(采集时间) | CS 拉低后采样电容充电需要多久 | 0.5 μs | CS 低后到发 SCK 之间等 ≥0.5μs |
| RSC(时钟周期) | SCK 最短脉冲 | 20 ns | SPI 时钟 ≤ 50MHz |
// 严格按照时序参数 void ADC_Read_Precise(void) { CS_Low(); Delay_500ns(); // RAC: 等采样电容充电 ≥0.5μs SPI_SetClock(40e6); // RSC: 40MHz < 50MHz 上限 uint16_t data = SPI_Read(); CS_High(); Delay_2us(); // RDC: 等转换完成 ≥1.6μs }总结
| 4 线 SPI | 5 线 SPI | |
|---|---|---|
| 信号线 | CS+SCK+MOSI+MISO | +BUSY |
| 怎么知道外设好了 | 延时硬等 | BUSY 变低通知 |
| 可靠性 | 延时设短了读错 | 硬件保证 |
| 速度 | 可能等太久 | 外设一好就通知 |
| MCU 引脚 | 省一根 | 多占一根 |
如果芯片有 BUSY 脚,一定要接上。靠延时硬等要么不可靠要么浪费 CPU 时间。
有用的话点个收藏,下次调试直接用。有问题欢迎评论区交流,看到了都会回。
