一句话: ADC 寄存器地址写成了 NOP 空操作,半年没发现——因为返回值被公式包装成了"合法负数"。翻数据手册逐位对照 SPI 帧格式才找到这个bit级的错误。
适合谁读:SPI 通信不正常但"看起来有返回值"的嵌入式开发者。
现象
读 ADC 的 4 路数据全是死值,但死值看起来"正常"——不是 0x0000 或 0xFFFF,是带公式换算后的负数,像 -5000mV。读代码的人第一反应是"硬件接错了",不是"寄存器地址写错了"。
查了三轮
第一轮:怀疑基准电压没开。改了电源配置寄存器,数据不动。后来确认基准本来就是开的,还原。
第二轮:怀疑 SPI 读数据的时机不对。SPI 有个惯例——当前帧返回上一帧的结果。代码在第 3 帧读数据,但 ADC 结果在第 2 帧就返回了。把读数据时机提前,数据还是不动。
第三轮:翻数据手册,逐位拆 SPI 帧格式。
手工拆一个寄存器地址
数据手册给出的 SPI 帧格式(16 位):
| D15 | D14:D11 | D10:D9 | D8:D0 |
|---|---|---|---|
| 0(写) | 寄存器地址 | 保留00 | 数据 |
寄存器映射表:
0000 = NOP(空操作) 0001 = DAC 回读 0010 = ADC 序列寄存器 ← 要操作的是这个 0011 = 通用控制 0100 = ADC 引脚配置代码里写的是Spi_Tx_Buff[0] = 0x01。拆成二进制:
0x01 = 0000_0001 D15=0, D14:D11=0000, D10:D9=00, D8:D0=001 寄存器地址 = 0000 = NOP写了 NOP 空操作——不启动任何转换。ADC 从未被触发过,当然读到的全是 0。正确的值是0x10:
0x10 = 0001_0000 D15=0, D14:D11=0010, D10:D9=00, D8:D0=000 寄存器地址 = 0010 = ADC_SEQ一个 bit 的差别:0x01 把 D4 写成 0,0x10 把 D4 写成 1。半年没人发现。
为什么半年没发现
返回值被公式包装了。ADC 读回 0,经过电压换算公式变成 -5000mV——一个看起来"有意义的负数",而不是裸的 0x0000。"有值"的表象掩盖了"值是错的"这个事实。
如果直接打印原始 ADC 码值而不是换算后的工程值,第一天就能发现 4 路全是 0。
怎么避免
读 SPI 器件返回值异常时,先看原始寄存器值,再看物理量换算值。裸的 0x0000 比 -5000mV 直观得多。
写寄存器地址时对着手册逐位拆一次。0x10和0x01这种差一个 bit 的拼写,肉眼扫过去根本看不出来。
有用的话点个收藏,下次调试直接用。有问题欢迎评论区交流,看到了都会回。