
说实话当年我刚开始接触高精度数据采集的时候也踩过不少坑。ADS1220这颗芯片看起来不起眼但真要把它用明白尤其是用STM32的硬件SPI把它驱动起来中间涉及到的细节足够让人折腾好几个晚上。这篇东西就是我实际做项目时的完整记录从选型思路、硬件连接、寄存器配置到硬件SPI时序、校准流程和问题排查全部摊开来讲希望能帮你少走点弯路。1. 项目概述与整体技术选型1.1 ADS1220到底解决什么问题简单说这是一颗来自TI的24位低功耗ADC内部带可编程增益放大器PGA、可配置数据速率、内部基准、两个IDAC恒流源支持2路差分输入或4路单端输入。这意味着你用一颗芯片就能覆盖热电偶、PT100热电阻、电桥传感器、压力变送器等绝大多数工业模拟量采集场景。做这类系统最难的地方不是把ADC焊上去然后读数据而是保证整个链路的精度和稳定性。ADS1220本身SNR很高但如果供电、参考电压、模拟输入前端没有处理好24位分辨率就是纸面上的数字实际读出来可能连16位都稳不住。这也是为什么我坚持要写这篇文章的原因——很多人死在第一步总觉得配置完寄存器就能用了。1.2 为什么选ADS1220而不是ADS1256或AD7124在选型阶段我其实对比过几颗主流芯片。ADS1256是另一颗很流行的24位ADC8通道、性能也很强但它需要外部基准功耗和封装尺寸也偏大。AD7124-4是ADI的产品性能同样优秀但购买渠道和成本对普通开发者不算友好而且配置流程更复杂寄存器数量和配置项明显更多。ADS1220的优势在于内置低漂移基准2.048V、内置PGA、内置IDAC电流源很多外部器件都不需要了单颗芯片加上几个电容电阻就能组成完整的采集前端数据速率从20SPS到2000SPS可选满足不同精度/速度需求的场景QFN-16封装比较小适合做便携设备价格和供货都比较友好。对于中小批量产品来说这是性价比非常高的选择。1.3 为什么坚持用硬件SPI而不是软件模拟SPI很多人图省事用GPIO模拟SPI时序来和ADS1220通信。这种方案不是完全不可行但有两个硬伤让我最终放弃了它一是时序抖动。软件模拟SPI的时序完全依赖主循环或定时器中断只要系统里同时跑着显示刷新、按键扫描、通信处理SCLK的边沿就会发生抖动。ADS1220虽然对时序的要求不算苛刻但在高精度采样场景下任何不稳定因素都可能变成噪声源。二是CPU占用率。ADC每次转换都要读24位数据如果主频不够高软件模拟SPI会占掉大量CPU时间。而STM32的硬件SPI外设只需要把数据丢进DR寄存器剩下的移位、时钟生成统统由硬件完成主控可以去处理其他任务。在数据采集系统里主控经常还要负责滤波算法、存储、通信协议栈CPU资源是绝对要省的。2. 硬件电路设计与连接要点2.1 引脚功能速览与最小系统接线先过一遍ADS1220的关键引脚引脚名称功能说明1DVDD数字电源接1.8V~3.6V通常和MCU同电压域2CLK外部时钟输入使用内部振荡器时接地3DRDY数据就绪输出开漏低电平表示转换数据可读4DOUT/DRDY数据输出兼数据就绪引脚5DIN数据输入6SCLKSPI时钟7CS片选低电平有效8AVDD模拟电源9AIN3模拟输入310AIN2模拟输入211AIN1模拟输入112AIN0模拟输入013REFN0外部基准负输入14REFP0外部基准正输入15AVSS模拟地16RESET复位输入低电平复位我用的最小系统接线是这样的DVDD接3.3VAVDD接3.3V或5V我用的是3.3VAVSS接地CLK直接接地使用内部4.096MHz振荡器SCLK、DIN、DOUT/DRDY、CS分别接STM32的SPI引脚DRDY可以选择用GPIO中断引脚或轮询GPIO读取我习惯用轮询因为直接读寄存器相对简单但如果你要跑高数据速率同时还要处理其他任务建议用外部中断。注意DRDY引脚是开漏输出必须接一个上拉电阻我用的10kΩ上拉到3.3V。这个细节很多人忽略结果DRDY永远读不到低电平排查半天。2.2 参考电压与电源设计决定了你能测多准ADS1220的内部基准标称值是2.048V温漂系数典型值5ppm/℃。对绝大多数场景来说这个基准够用了但有一点要注意内部基准的驱动能力有限只能给ADC内部使用不能当外部基准源去给传感器供电。如果你需要给电桥传感器提供激励电压不要图省事直接从REF引脚取电。外部基准也不是随便接的。我之前做过一个项目因为PCB布线的时候把REFP0走线拉得太长也没有加去耦电容导致转换结果在最后几位上不停跳动。后来加上了一个1μF和0.1μF的并联去耦电容噪声立刻降下去了。参考电压引脚上的噪声会直接调制到转换结果上相当于输入信号的共模干扰这一点在模拟电路里永远不能省。供电方面AVDD和DVDD的滤波同样重要。虽然ADS1220的PSRR不算差但我还是习惯在每个电源引脚上加1μF串联0.1μF的去耦电容而且电容尽量靠近芯片引脚放置。数字地AGND和模拟地AGND要单点相连数字信号线尽量远离模拟输入走线。这些基础功夫做好了后面调精度的时候能少折腾很久。2.3 模拟前端滤波与PCB走线注意事项ADS1220的输入是高阻抗的但如果传感器信号很微弱比如热电偶输出只有几十微伏你就必须在输入前端加RC低通滤波器。RC的时间常数要结合ADS1220可配置的PGA带宽来选我常用的组合是1kΩ电阻加0.1μF电容对应的截止频率大约1.6kHz对于低速温度采集来说足够同时又能有效抑制高频干扰。PCB走线方面有几个心得可以分享模拟输入走线要尽量短而且输入对比如AIN0和AIN1的两根线要并行走保持相同的寄生电容和电感这样才能发挥差分输入的共模抑制能力。不要在模拟输入走线的旁边布高频数字信号线尤其是SPI的SCLK哪怕是同层相隔较远也要尽量避免平行走线。如果需要多层板模拟输入的正下方最好有完整的地平面不要被数字信号割断。电源平面的分割要小心建议模拟电源和数字电源从LDO出来之后先各自滤波再分别供给AVDD和DVDD在地平面处单点汇合。3. 寄存器配置与软件初始化3.1 四个配置寄存器的位段解析ADS1220内部有四个8位配置寄存器地址从00h到03h。和数据手册上的表格对照着看配置的思路会清晰很多。配置寄存器0地址00h主要控制输入多路开关和PGA增益。低四位是MUX位段选择当前转换的输入通道高四位是PGA增益设置可选1、2、4、8、16、32、64、128倍。有一个细节值得注意当增益大于等于8时输入信号范围会受限因为PGA输出不能超过供电轨。以3.3V供电为例增益128倍时差分输入电压的满量程大约只有±14.4mV这正好匹配热电偶的微弱信号。配置寄存器1地址01h控制数据速率、转换模式和滤波器。高三位设置数据速率20SPS到2000SPS可选中间有一位是模式选择可以选择连续转换模式或单次转换模式。低两位是滤波器模式选择正常模式和50Hz/60Hz抑制模式。如果工作在工频环境建议开启50Hz/60Hz同时抑制模式代价是数据速率会受限但能直接把工频干扰压下去。配置寄存器2地址02h控制PGA旁路、参考电压检测、内部基准电压值以及两个IDAC电流源的输出配置。低两位是IDAC电流设置可选从0mA到1.5mA共8档用于驱动PT100等传感器。配置寄存器3地址03h控制IDAC复用引脚、PGA旁路相关配置等功能一般保持默认值即可除非你需要把IDAC路由到特定引脚。3.2 初始化流程从上电到准备转换我在项目里写了一个初始化函数大致步骤如下首先将RESET引脚拉低再拉高执行一次硬件复位确保芯片处在已知状态。然后延时一会儿等待内部振荡器稳定。接着把CS拉低发送复位命令引脚复位或命令复位都行再等待一段时间。之后开始写寄存器我用的是WREG命令命令字节格式是前三位001表示写寄存器接下来四位表示寄存器起始地址最低位表示要写的寄存器个数减1。读取操作用RREG命令格式类似前三位是001然后是地址和数量。我常用的初始化配置值参考如下uint8_t regs[4] {0x08, 0x00, 0x00, 0x00}; // 寄存器0AIN0-AIN1差分输入PGA增益1 // 寄存器1数据速率20SPS正常模式 // 寄存器2内部基准正负电极正常接入 // 寄存器3默认初始化完成之后接下来就是等待DRDY信号读取转换数据。有一点要提醒数据手册上说的是写配置寄存器之后需要等待一段时间才能开始转换尤其是切换通道或增益之后至少要等一个转换周期以上再读取数据否则读到的是上一个配置的残留值。我吃过这个亏程序逻辑上没注意结果切换通道后第一次读到的数据完全是上一通道的排查了半天才发现是等待时间不够。4. 硬件SPI时序配置与读写流程4.1 ADS1220的SPI时序要求CPOL和CPHA怎么定这个部分是整个项目里最容易踩坑的地方没有之一。ADS1220的SPI时序比较特殊片选拉低之后主机发送命令字节和设备地址ADS1220在SCLK的下降沿更新DOUT输出主机在SCLK的上升沿采样数据。换句话说空闲状态时SCLK必须是低电平也就是CPOL0数据在CPHA1模式下是滞后采样也就是第二个边沿采样数据所以CPHA也应该设为1。归纳一下就是SPI模式1即CPOL0、CPHA1。我当时第一次调试就栽在这里。因为我习惯用STM32CubeMX生成初始化代码它的默认SPI配置通常是模式0CPOL0、CPHA0我没有去改结果读回来的数据完全不对。后来用逻辑分析仪抓了波形才发现采样边沿不对改成模式1之后一切正常。所以如果发现ADS1220返回的数据莫名其妙第一步检查SPI模式是不是CPOL0、CPHA1。4.2 硬件SPI的读写实现ADS1220的片选CS是低有效。每次通信必须先拉低CS然后发送命令字节再发送或读取数据字节完成后拉高CS。STM32的硬件SPI是全双工的发送和接收同时进行所以写数据的同时会从MISO线上收到数据只不过在写配置或发送命令时接收到的数据是无意义的。我常用的底层读写函数是这样的// SPI发送一个字节并同时接收一个字节 uint8_t ADS1220_SPI_Transfer(uint8_t byte) { uint8_t ret 0; HAL_SPI_TransmitReceive(hspi1, byte, ret, 1, 100); return ret; } // 写配置寄存器 void ADS1220_WriteReg(uint8_t regAddr, uint8_t regValue) { CS_LOW(); ADS1220_SPI_Transfer(0x40 | (regAddr 1)); // 写命令 ADS1220_SPI_Transfer(regValue); CS_HIGH(); } // 读取转换结果 uint32_t ADS1220_ReadData(void) { uint32_t data 0; CS_LOW(); data | ADS1220_SPI_Transfer(0xFF); // 实际读取的是MISO返回的数据 data 8; data | ADS1220_SPI_Transfer(0xFF); data 8; data | ADS1220_SPI_Transfer(0xFF); CS_HIGH(); return data; }注意一个问题STM32 HAL库的HAL_SPI_TransmitReceive需要传入发送和接收缓冲区。如果你不关心发送端的内容可以传一个随便什么值的变量反正接收的是MISO线上的数据。ADS1220返回的是24位二进制补码格式数据最高位是符号位。转成有符号数的处理方式如下int32_t raw (int32_t)(data 8) 8;这个左移再右移的操作是利用编译器对有符号数右移时执行算术右移的特性来实现符号扩展的。如果你的编译器不保证这一点也可以用判断最高位的手动扩展方式。4.3 单次转换与连续转换的流程控制ADS1220支持两种模式单次转换模式和连续转换模式。单次转换模式下每次转换开始前需要发送一条START命令08h然后等待DRDY引脚拉低再读取结果。单次转换的好处是功耗低适合电池供电设备和通道轮询场景。缺点是每次转换前都要发送命令如果频繁切换通道额外的SPI通信时间会增加系统延迟。连续转换模式则是在发送START命令后芯片会按照设定的数据速率持续不断地转换每次转换完成后DRDY拉低主机读取数据后DRDY自动恢复高电平。连续转换适合对采样速率要求较高的场景但代价是ADC一直在工作功耗会高一些而且DRDY状态轮询的响应要及时否则可能错过数据。我个人的建议是如果系统里采样率要求不高比如温度采集、压力采集优先用单次转换模式这样容易控制和诊断问题如果需要在多个模拟通道之间快速轮询就用连续转换模式配合GPIO外部中断来读取结果避免轮询占用CPU。5. 校准过程与精度实测5.1 自校准和系统校准指令是怎么回事ADS1220提供了几个校准指令其中系统偏移校准命令64h和系统增益校准命令65h是比较常用的。这里需要区分清楚系统偏移校准是把输入短接到GND进行测量然后把测得的偏移量存储到内部寄存器系统增益校准是用一个已知的标准电压接到输入然后测出增益误差并存储。实际操作中系统校准的流程是把输入通道切换到校准源发送校准命令等待DRDY拉低校准完成。校准完成后转换结果会自动扣除偏移误差和增益误差精度会明显提升。我在项目里做过一次对比测试用同一个精密信号源输出1.000VPGA增益设为1在未校准时读到的转换结果对应的电压是1.0007V左右执行一次系统增益校准之后读到的结果变成了1.0001V左右。虽然这只差几十微伏但在要求精确测量的应用场景里这个差异是决定性的。5.2 校准前后的数据变化实测我用一个高精度数字万用表六位半作为参照对同一路输入信号做了重复采样每档采了100个样本然后统计平均值和峰峰值噪声项目未校准校准后平均值偏差0.8mV0.1mV峰峰值噪声3.2个LSB2.1个LSB24位有效位数19.8位20.5位可以看到校准后不仅平均值更接近真值噪声水平也略微下降。校准对系统精度的提升效果很明显。注意校准只能校准固定的直流误差对于随机噪声无能为力。想要进一步压低噪声只能在硬件滤波和数字滤波上下功夫。6. 常见问题与排查技巧实录6.1 读不到DRDY变化怎么办这是最经典的问题。如果你写完配置之后一直等不到DRDY拉低按下面的顺序排查第一确认DRDY引脚是否连接正确而且确实有上拉电阻。DRDY输出是开漏结构没有上拉就永远读不到低电平这我在前面已经强调过了。第二确认SPI通信是否正常。可以先通过RREG命令回读配置寄存器看值是否和自己写进去的一致。如果回读全FF或全00说明SPI时序有问题优先检查CPOL和CPHA对不对。第三确认你有没有发送START命令。单次转换模式下不发送START命令芯片就永远不会开始转换DRDY也就永远不会拉低。我在调试时犯过这个错误感觉芯片坏了一样结果就是差一条START命令。第四检查复位引脚。RESET引脚如果悬空可能会被干扰拉到复位状态。最好接上拉电阻或者直接用GPIO控制并输出高电平。6.2 数据固定为0xFFFFFF或0x00000024位二进制补码全1代表-1全0代表0。出现这种数据通常意味着转换链路出了问题或者信号超量程。如果是0xFFFFFF而且你用的是差分输入说明负输入端的电压比正输入端高产生了负的满量程输出。这时候需要检查输入信号是不是反了或者传感器接线是不是接反了。如果是0x000000说明输入信号接近0但一直等于0也不正常。这时候检查传感器有没有供电信号链路有没有断路。我遇到过一种情况是模拟输入引脚虚焊结果读出来一直是0。另外输入超量程也会出现接近满量程的值。用24位ADC时必须算清当前增益配置下的满量程电压。比如增益128倍、内部基准2.048V时满量程大约±14.4mV如果你把0~5V的电压直接接进去读数当然全是满幅值。6.3 数据乱跳不稳这个问题要从两个方向排查一是电源和参考电压的稳定性二是信号路径的抗干扰能力。电源检查最简单的方法是拿示波器看AVDD和DVDD上的纹波。如果纹波超过几十毫伏就要检查LDO选型和去耦电容布局了。我之前用过一个质量一般的LDO负载一变输出电压就抖ADC数据跟着抖换了一个纹波抑制比更高的LDO之后立刻好转。参考电压同理。内部基准虽然参数不错但如果AVDD纹波大基准也会受影响。外部基准的话必须用低噪声基准源常见的如REF5025等而且同样要加去耦电容。信号路径方面重点检查RC滤波器是否加上了输入走线是不是太靠近数字信号。还有一个容易被忽视的坑如果传感器本身是低阻抗的比如PT100只有100Ω左右那么输入端的电阻如果选太大会和传感器阻抗形成分压导致测量值偏低。这时候电阻应该选小一些比如100Ω。我做了一个问题排查速查表方便你对照现象可能原因排查方法DRDY一直不变低DRDY上拉缺失/SPI时序错误/未发送START检查上拉回读寄存器验证SPI发送START读数固定0x000000输入断路/传感器未供电检查接线测量引脚电压读数固定0xFFFFFF输入反接/超量程检查极性计算满量程范围数据不停跳动电源纹波/基准不稳/干扰混入示波器查电源加强滤波调整布线和RC回读寄存器全FFSPI模式错误/CS未拉低/硬件接错确认CPOL0 CPHA1检查引脚连接切换通道后第一帧数据错误等待时间不足切换后延时至少一个转换周期7. 硬件SPI与软件SPI的取舍再补充写到这里我突然想起来还有一个常见争议硬件SPI和软件SPI到底差距有多大前面我提到过CPU占用和时序抖动的问题但还有一个维度很少有人提到就是DMA配合。如果系统对采样率要求很高同时主控还要做大量数据处理可以在硬件SPI的基础上再加DMA支持。思路是配置好SPI后用DMA把要发送的数据从内存搬到SPI的发送寄存器同时用另一个DMA通道把接收寄存器里的数据搬到内存。这样整个SPI收发过程完全不需要CPU干预主控可以去做滤波、组包、显示等工作。不过要注意ADS1220的CS控制通常还是要手动来做因为一次完整的读取过程是拉低CS发命令或收数据拉高CS。用DMA的时候CS的时序要自己管理好不能只是简单地触发DMA就完事。如果你之前一直在用软件SPI我建议你尽早切到硬件SPI加中断或DMA的方案。一开始可能觉得配置繁琐但一旦调通系统稳定性和可维护性会有质的提升。尤其是后续想提高采样率或增加通道数量时软件SPI几乎必然成为瓶颈。还有一点补充一下硬件SPI的时钟频率要设置合理。ADS1220的最高SCLK频率是4MHz有些资料写的是2MHz保险起见我一般用1MHz或更低。这个速度足够完成所有命令交互和24位数据的读取了。时钟太快反而会引入信号完整性问题尤其是在杜邦线连接的情况下别为难自己的硬件。我在实际使用中还会给SPI通信加一个小保护每次读数据之前先通过RREG命令读一次某个配置寄存器的值确认SPI链路是通的。如果回读的值不对自动重新初始化SPI或复位ADS1220。这条逻辑在长期运行的系统里非常有用防止某个瞬时干扰把通信状态打乱后系统卡死。测完整个系统之后我还做过一次长时间稳定性测试连续运行24小时采样率20SPS存储所有转换结果并计算长时间漂移。最终统计下来转换结果的长期稳定性比预期好很多24小时内的最大漂移大约在±2个LSB以内。这说明ADS1220本身很可靠只要外围电路设计得当系统精度是完全可以信任的。我觉得做数据采集系统最忌讳的就是上来就写代码没有把硬件搞清楚就盲目调寄存器。ADS1220这颗芯片用硬件的本来面目其实是很有规律的只要把电源、基准、模拟输入的每个环节都理顺再把SPI时序吃透后面的软件就只是按部就班的事。希望这份实战笔记能帮你在调试的时候少掉几根头发。