一句话: 同一条 SPI 总线上挂了不同模式、不同帧长的芯片——初始化设成 16 位后,另一个要 24 位命令的芯片就不工作了。切回 8 位后,16 位的芯片要拆字节收发。一个能用另一个不能时别急着怀疑芯片坏了。
适合谁读:SPI 总线上挂了多个器件,一个正常一个不正常的嵌入式开发者。
问题
一条 SPI 总线挂了三颗芯片:
| 芯片 | 帧长 | 模式 |
|---|---|---|
| ADC | 16 位 | Mode 3 |
| DAC | 24 位命令 | Mode 0 |
| Flash | 8 位 | Mode 0 |
初始化把 SPI 设成 16 位模式——为兼容 ADC。DAC 的命令格式是 3 字节(24 位),用 16 位模式发——每个 SPI 帧都是 16 的倍数个 SCK。DAC 要求精确 24 个 SCK,收到 32 个就把命令丢了。输出永远是 0V。
统一切 8 位
方案:SPI 统一设成 8 位模式。这是最小公约数——16 位和 24 位都能用 8 位拼出来。
DAC(24 位命令)——三个字节一发:
// 3 字节 = 24 SCK,刚好 Spi_Tx[0] = CMD; Spi_Tx[1] = Data >> 8; Spi_Tx[2] = Data & 0xFF; SPI_Transmit(buf, 3);ADC(16 位数据)——拆成两个 8 位收发再拼接:
// 发:高 8 位 → 低 8 位 SPI_Send(Data >> 8); SPI_Send(Data & 0xFF); // 收:高 8 位 → 低 8 位 RxData = SPI_Receive() << 8; RxData |= SPI_Receive();8 位是 SPI 总线多器件场景的通用开关。把所有 SPI 初始化统一到 8 位,每种器件在自己的读写函数里负责字节拼接。
为什么一个能用另一个不能用
ADC 一直在正常读数——让你反复怀疑"SPI 是通的啊,DAC 芯片坏了吧"。但 SPI 总线信号是分时复用的——每个器件选中时用自己的 SPI 参数通信。ADC 的 CS 拉低时用它的配置通信没问题,DAC 的 CS 拉低时用另一个配置——错了。
CS 管的是"谁在说话",不管"按什么规矩说话"。规矩是初始化时全局设的,不同器件的规矩不同就打架。
除了帧长还有模式
切完帧长后 DAC 还是没输出。示波器一打——SCK 在跳、MOSI 在发、CS 正常,但就是没输出。翻 DAC 手册的时序图——要求 Mode 0(CPHA=0,上升沿锁数据)。初始化里设的是 Mode 1。
改了 CPHA 后所有器件重测一遍——ADC 也能用 Mode 0,Flash 也是 Mode 0。DAC 终于有输出了。
经验
一条总线多器件的调试顺序:先用示波器量每个器件的 CS/SCK/MOSI 波形 → 确认帧长(数 SCK 脉冲数)→ 确认模式(看 SCK 和 MOSI 的相位关系)→ 翻手册逐项对照。
CS 拉低后 SPI 正常不代表每个器件都按同一套规矩工作。帧长和模式是全局的,但要求是各器件各自的。
有用的话点个收藏,下次调试直接用。有问题欢迎评论区交流,看到了都会回。