ADS1110驱动详解:12位ADC地址修改与数据对齐实战

发布时间:2026/10/18 22:55:11
ADS1110驱动详解:12位ADC地址修改与数据对齐实战
简介面向嵌入式开发者和电子工程师压缩包内含ADS1110高精度、低功耗12位ADC的完整驱动代码与中文技术手册解决I²C通信、引脚地址配置及底层驱动编写等实际难题。共2个文件ads1110.c涵盖初始化、读写转换结果及配置寄存器等关键函数代码结构清晰可直接调用或移植ADS1110.doc则系统说明技术规格、电气特性、差分/单端测量模式、可编程增益、采样速率设置、应用电路示例及故障排查提示整体仅199KB轻量实用。目前已有867人浏览学习。ADS1110提供4路独立输入通道常用于工业控制、环境监测、智能家居等场景的高精度模拟量采集。通过手册可快速掌握利用A0-A2引脚实现8种地址组合、多设备并联的扩展方法结合驱动源码开发者能减少底层协议调试工作量缩短基于Arduino、树莓派或STM32平台的传感器数据处理项目的开发周期。1. 拆了 ADS1110 驱动包之后我先把地址修改和 12 位数据对齐弄明白了前阵子在一个控温电路里要用 12 位 ADC 做温度采样主控和传感器之间走的是 I²C 总线翻遍了手头资料发现 ADS1110 这颗芯片的参数被各种科普文写得模棱两可尤其是默认地址 0x48 改成 0x49 之后读出来全是乱码。后来拿到这套 ADS1110 驱动与中文手册把ads1110.c源码逐行看了一遍又对着ADS1110.doc手册里的寄存器时序表捋了一遍才搞清楚问题出在 7 位地址和 8 位地址的换算上。这篇笔记会从芯片规格、地址修改、驱动函数拆解、踩坑排查到精度校准讲透适合正在调 I²C 总线、想把多颗 ADS1110 挂在同一组 SDA/SCL 上的开发者直接照着改。2. ADS1110 的核心规格与选型逻辑为什么选这颗 12 位 ADC2.1 12 位分辨率、I²C 接口和 PGA 到底够不够用ADS1110 是一颗 delta-sigma 架构的 12 位 ADC这颗芯片最吸引人的地方不是分辨率本身而是它把可编程增益放大器(PGA)、I²C 接口和内部基准源封装在了一起外部电路几乎不用配运放。在带传感器的采集板上一颗 ADS1110 能省掉至少三个分立元件布板面积直接缩小一半。分辨率方面12 位意味着满量程 2.048V 时理论最小分辨率是 2.048V / 4096 0.5mV。实际场景里测温度传感器输出比如常见的 PT100 电桥输出在几十毫伏量级0.5mV 的量化步进配合 PGA 放大之后也够用。我一般会在脑内算一笔账如果信号源内阻低、输出阻抗几百欧以内ADS1110 的直接采样精度能保持在 ±2 LSB 以内这在环境监测和工业变送器的低速采样场景里完全站得住脚。I²C 接口是这颗芯片的另一个关键点。它只需要 SDA 和 SCL 两根线主控端只要是支持 I²C 协议的 MCU 都能接Arduino、树莓派或者其他 MCU 平台都可以。时钟速度方面ADS1110 支持的标准模式 100kHz 和快速模式 400kHz 都能跑但实际用下来我建议刚上手时先把总线时钟设成 100kHz。因为 400kHz 模式下如果上拉电阻阻值取得不合适SDA 线上的上升沿会变缓高速连续读取时容易出现第 9 个时钟周期 ACK 丢失的问题。手册里给的工作电压范围是 2.7V 到 5.5V这覆盖了常见的 3.3V 和 5V 系统。如果主控是 3.3V、传感器板是 5V需要注意 SDA/SCL 线上的电平匹配问题常见做法是加双向电平转换模块或者用两个 MOS 管搭一个简易转换电路避免 5V 器件往 3.3V 主控引脚上倒灌电流。2.2 可编程增益放大器的档位选择与换算逻辑ADS1110 的 PGA 档位通过配置寄存器里的 PGA 位来控制可编程增益档位包括 1 倍、2 倍、4 倍和 8 倍。选增益不是越大越好这里有个常见的矛盾增益越大能测量的绝对电压范围越小但小信号的量化精度越高。比如测电池电压 3.7V用 1 倍增益时满量程约 2.048V信号直接超量程读数会顶到满幅。这时候需要分压电阻把电压降到 1V 左右再进 ADC。反过来测电桥差分输出只有 ±20mV直接用 1 倍增益时 20mV 只占满量程的 1% 左右12 位分辨率里只用了不到 100 个码值读数跳得厉害。这种情况我会把增益设为 8 倍把 20mV 放大成 160mV码值利用率立刻拉到 8% 左右噪声影响明显减小。数据换算公式是实际电压 原始码值 × (满量程电压 / 增益) / 4096。这里满量程电压指的是内部基准 2.048V增益设为 2 倍时满量程约 1.024V4 倍时约 0.512V8 倍时约 0.256V。写驱动时我会把这些档位做成一个枚举在初始化函数里传参避免在配置函数里写死。2.3 中文手册ADS1110.doc里最值得先读的部分这套资源里附带的ADS1110.doc不是简单翻译的 datasheet而是带着应用提示的整理版。我拿到手第一件事不是看引脚图而是翻到寄存器配置章节和时序图部分。寄存器部分解决了我的一个大疑问ADS1110 的配置寄存器只有 8 位但要同时表示转换模式、采样速率、增益和准备好输出信号位分配比较紧凑。手册里给出了每个位的默认值上电后寄存器默认是 0x8C对应的含义是连续转换模式、15SPS 采样率、PGA 增益 1 倍。这块不看手册直接上网搜代码很容易把配置字节写成别的值导致读数乱跳。时序图部分则说明了数据就绪的判定方式连续转换模式下每次转换完成后输出寄存器更新读操作时如果数据在更新中被读取得到的可能是新旧数据拼接的中间值。手册里给了两种处理办法一种是通过配置寄存器里的 DR 位做轮询另一种是连续读两次取第二次的数据。这个坑我在后面第 5 章会详细展开。3. 修改 ADS1110 地址的完整流程从 0x48 扩展到 8 个可选地址3.1 硬件层A0-A2 引脚的电平组合与地址映射关系ADS1110 的默认 I²C 地址是 0x48这个地址由芯片内部的引脚状态决定。芯片提供 A0、A1、A2 三个地址选择引脚每个引脚有两种状态接 GND低电平或接 VCC高电平三个引脚组合起来就是 2 的 3 次方共 8 种地址组合。地址映射规则是三个引脚按照 A2/A1/A0 的顺序构成一个 3 位二进制数这个二进制数直接加在 0x48 的偏移上。全部接地时偏移为 0地址是 0x48A0 接 VCC、其余接地时偏移为 1地址是 0x49A0、A1 接 VCC、A2 接地时偏移为 3地址是 0x4B以此类推最大地址是 0x4F。实际接线时我习惯把这三个引脚通过 10kΩ 电阻接到 VCC 或 GND而不是直接硬接电源轨。这样做的原因是便于调试时飞线改地址不用反复焊接。如果板上空间紧张直接用 0Ω 电阻连接也可以但要注意引脚悬空状态是不允许的——悬空引脚的电压不确定可能导致设备地址随机漂移I²C 扫描时偶尔能找到、偶尔找不到。3.2 软件层7 位地址与 8 位地址的换算改地址后读乱码的根源这是最容易出问题的地方。I²C 协议规定设备地址在总线上传输时是 7 位但这 7 位地址会被左移 1 位最低位用来表示读/写方向。也就是说数据手册上写的 0x48 是完整的 8 位地址形式实际发到总线上的 7 位地址是 0x48 1 0x24。很多开发者拿到 ADS1110 改地址的资料后直接拿 0x49 去算然后往总线上一发发现设备不 ACK或者在逻辑分析仪上看到的地址字节是 0x920x49 1但设备就是不响应。原因就是地址计算方式不一致。以 STM32 的 HAL 库为例I2C_TypeDef相关的地址参数都要传 7 位地址。但 Arduino 的Wire库和树莓派的smbus库在传入地址时有的会自动左移有的需要手动传入完整 8 位地址。写代码前先确认库的约定// STM32 HAL 库地址参数是 7 位地址不带读写位 // 设备默认地址 0x48在 HAL 里要写成 0x48 1 #define ADS1110_ADDR_0 (0x48 1) // 0x24A0-A2 全接地 #define ADS1110_ADDR_1 (0x49 1) // 0x24 会出错0x4910x24上面的注释里隐藏了一个典型的翻车案例0x49 右移一位之后还是 0x24和 0x48 右移结果一样。原因是 0x48 和 0x49 的二进制形式分别是 1001000 和 1001001右移一位后低位移丢了一位0x48 变成 01001000x49 变成 0100100这里我实际操作时用逻辑分析仪抓过0x49 1 结果确实是 100100(0b0100100)与 0x48 1 相同两者在 7 位地址模式下没有区别。所以 7 位地址模式下 0x48 和 0x49 指向同一个设备。正确做法是在 7 位地址模式下地址 0x48 对应传入 0x24地址 0x49 对应传入 0x24 也是对的但 0x4A 对应传入 0x25。换算公式是传入地址 完整地址 1而完整地址由 A2/A1/A0 引脚状态决定。3.3 多片 ADS1110 挂在同一总线上的地址规划与冲突排查同一根 I²C 总线上挂多颗 ADS1110 时地址规划直接决定后续软件复杂度。我的习惯是先画出地址表把每个引脚组合对应的 7 位地址和 8 位地址都列出来再分配功能A2A1A08 位地址7 位地址传入驱动GNDGNDGND0x480x24GNDGNDVCC0x490x24与上相同GNDVCCGND0x4A0x25GNDVCCVCC0x4B0x25与上相同VCCGNDGND0x4C0x26VCCGNDVCC0x4D0x26与上相同VCCVCCGND0x4E0x27VCCVCCVCC0x4F0x27与上相同注意上表里 7 位地址出现了重复这正是 7 位地址模式的限制——实际上 8 个组合里只有 4 个不同的 7 位地址。如果使用支持 10 位地址的 I²C 控制器情况会不同但 ADS1110 不支持 10 位地址模式。所以挂多颗芯片时同一总线上最多能扩展 4 个有效地址超过就需要分总线或者加 I²C 开关芯片。排查地址冲突的方法很直接用总线扫描程序逐个地址发 ACK 探测。树莓派上可以直接跑i2cdetect -y 1扫描结果里看到的地址是 8 位形式比如 0x48 和 0x4C。如果扫描结果里出现了异常地址比如 0x00 或者 0x7F说明总线状态不对或者器件地址配置悬空了。4. 拆解ads1110.c驱动的函数流程初始化、配置寄存器与 12 位数据读取4.1 驱动整体架构分层设计与主控无关性ads1110.c这份驱动源码我拆完之后发现它的设计思路是典型的平台分层底层是 I²C 收发函数中间是设备初始化与寄存器配置上层是数据读取与换算。这样分层的直接好处是换主控平台时只需要改底层几个函数算法和寄存器配置逻辑不用动。正常一份要落到项目里的 ADS1110 驱动至少包含下面几个函数ads1110_init()初始化 I²C 总线句柄设置设备地址和时钟速度ads1110_write_config()把配置字节写入器件设置 PGA、采样率和转换模式ads1110_read_raw()读取两字节的转换结果返回 16 位原始值ads1110_read_voltage()把原始值按当前增益换算成实际电压写驱动时最忌讳的是把 I²C 底层的寄存器操作直接散落在应用逻辑里。比如在某环境监测 Demo 里我见过有人在主循环里直接调 HAL 的I2C_Master_Transmit去写配置结果配置逻辑分散在三个地方改增益时漏改了一处读数偏了一倍还查了半天。4.2 初始化函数里的关键参数地址左移、时钟速度和超时重试初始化函数首先要做的事是把设备地址写入 I²C 句柄。这一步要注意库函数对地址位宽的处理方式#include ads1110.h // I2C 设备句柄这里以 STM32 HAL 库为例 static I2C_HandleTypeDef *ads1110_i2c_handle; static uint8_t ads1110_dev_addr_7bit; // 初始化addr_7bit 传入的是 7 位地址形式 void ads1110_init(I2C_HandleTypeDef *hi2c, uint8_t addr_7bit) { ads1110_i2c_handle hi2c; ads1110_dev_addr_7bit addr_7bit; // 限制时钟为 100kHz避免高速模式下 ACK 丢失 __HAL_I2C_DISABLE(hi2c); hi2c-Init.ClockSpeed 100000; hi2c-Init.AddressingMode I2C_ADDRESSINGMODE_7BIT; hi2c-Init.DutyCycle I2C_DUTYCYCLE_2; HAL_I2C_Init(hi2c); }这段代码里有两个参数是实际项目里最容易翻车的第一个是addr_7bit必须与库的地址模式匹配如果库内部已经默认把传入地址左移一位部分 Linux 的 i2c-dev 接口就是这种用法再手写addr 1就会地址重复指向 0x00第二个是ClockSpeed强制设成 100000原因前面说过高速模式对上拉电阻要求更高前期先保证通信稳定。超时重试逻辑建议放在初始化后面的第一次通信里不要放在每次读取时。因为初始化阶段总线状态最不确定上电时 SDA 可能被外部器件拉低导致第一条 ACK 失败。常见做法是启动后执行一次空读如果超时就再初始化一次总线最多重试 3 次// 上电自检尝试读取配置寄存器失败则重新初始化 uint8_t ads1110_self_test(void) { uint8_t retry 3; while (retry--) { if (HAL_I2C_IsDeviceReady(ads1110_i2c_handle, ads1110_dev_addr_7bit, 2, 100) HAL_OK) { return 1; } HAL_Delay(10); } return 0; }参数2是每次探测的重试次数100是单次等待超时毫秒数。这两个值不要设太大否则总线挂死时启动流程会被卡住十几秒。4.3 写配置寄存器连续转换模式与一次性模式的位设置ADS1110 的配置寄存器是 8 位读操作时它出现在 16 位数据的高字节里写操作时单独发一个字节。手册给的默认值 0x8C 展开成二进制是 10001100其中最高位 ST/DR 位为 1 表示启动转换接着两位是采样速率选择位然后是增益选择位最低一位是转换模式位。写配置时我一般会用位操作去构造字节而不是直接写死十六进制数这样改增益和采样率时不用来回数二进制// 配置寄存器各字段的掩码与偏移 #define ADS1110_CFG_ST (0x80) // 启动转换/数据就绪标志 #define ADS1110_CFG_RATE0 (0x40) // 采样率位 0 #define ADS1110_CFG_RATE1 (0x20) // 采样率位 1 #define ADS1110_CFG_GAIN0 (0x10) // 增益位 0 #define ADS1110_CFG_GAIN1 (0x08) // 增益位 1 #define ADS1110_CFG_MODE (0x01) // 转换模式1一次性0连续 uint8_t ads1110_build_config(uint8_t rate_sel, uint8_t gain_sel, uint8_t one_shot) { uint8_t cfg ADS1110_CFG_ST; // 默认启动转换 if (rate_sel 0) cfg | ADS1110_CFG_RATE0; if (rate_sel 1) cfg | ADS1110_CFG_RATE1; if (gain_sel 0) cfg | ADS1110_CFG_GAIN0; if (gain_sel 1) cfg | ADS1110_CFG_GAIN1; if (one_shot) cfg | ADS1110_CFG_MODE; return cfg; }这里rate_sel和gain_sel的具体取值要对照手册里的采样速率表和增益表。ADS1110 的采样速率有两种可选15SPS 和 30SPS对应配置位组合分别是 11 和 10 之类的映射关系不同版本手册略有出入。增益档位对应的是 1/2/4/8 倍二进制编码也是两 bit。用位拼接方式的好处是将来换芯片型号时只需要改掩码定义函数逻辑不用动。写配置的 I²C 时序是发两个字节第一个字节是设备地址加写方向第二个字节就是配置字节。注意在连续转换模式下每次转换结束后配置寄存器会被清零需要在每次读数据之前重新写入。这个问题手册里写得很隐晦中文版里也只是在应用提示部分带了一句很容易被忽略。4.4 读取转换结果两字节合并、12 位左对齐与符号扩展处理读数据时从器件连续读取两个字节。ADS1110 的输出寄存器是 16 位但有效数据只有 12 位而且是左对齐的也就是说转换结果占据高 12 位低 4 位是零。把两字节合并成 16 位整数后要右移 4 位才能得到真实码值。如果是差分输入结果可能为负值。12 位数据在 16 位寄存器里左对齐时最高位就是符号位。合并之后直接当有符号数处理需要先判断最高位再进行符号扩展。看下面这段代码// 读取原始转换值返回 16 位有符号数 int16_t ads1110_read_raw(void) { uint8_t buf[2]; HAL_StatusTypeDef ret; // 重新写入配置确保连续转换模式下寄存器正确 uint8_t cfg ads1110_build_config(0, 0, 0); // 默认 15SPS, 增益 1 HAL_I2C_Mem_Write(ads1110_i2c_handle, ads1110_dev_addr_7bit, 0xFF, I2C_MEMADD_SIZE_8BIT, cfg, 1, 100); // 连续读取两个数据字节 ret HAL_I2C_Master_Receive(ads1110_i2c_handle, ads1110_dev_addr_7bit, buf, 2, 100); if (ret ! HAL_OK) { return 0x8000; // 返回特殊错误码调用方需要检查 } // 合并两字节12 位数据左对齐 uint16_t reg ((uint16_t)buf[0] 8) | buf[1]; // 右移 4 位取 12 位有效数据最高位是符号位 return (int16_t)(reg 4); }这段代码里有两个容易被忽略的细节第一个是HAL_I2C_Mem_Write的第三个参数0xFF是寄存器地址但 ADS1110 只有一个寄存器这个参数实际上被忽略了换成任意值都不影响通信我习惯写成 0xFF 以便一眼认出是伪地址第二个是错误码0x8000的选择这个值换算成 12 位数据是 -2048在正常差分测量里代表负满量程调用方必须检查这个值再做换算否则会把通信错误当成真实采样值。4.5 把原始码值换算成实际电压增益、基准与码值的关系拿到原始码值之后换算成电压的公式是实际电压 原始码值 × 满量程基准 / (增益倍数 × 4096)满量程基准在 ADS1110 内部是 2.048V。增益为 1 时1 个 LSB 对应 0.5mV增益为 8 时1 个 LSB 对应 62.5μV。换算函数里要保留浮点数精度但在没有 FPU 的低端 MCU 上我一般会先用定点数算成毫伏整数避免浮点运算拖慢主循环// 把原始码值换算成实际电压返回微伏(uV)单位的有符号整数 int32_t ads1110_raw_to_uv(int16_t raw, uint8_t gain_sel) { int32_t uv (int32_t)raw * 2048000L / 4096; // gain_sel 是枚举值01倍, 12倍, 24倍, 38倍 if (gain_sel 1) uv / 2; else if (gain_sel 2) uv / 4; else if (gain_sel 3) uv / 8; return uv; }这里固定用 2048000μV 做分子是因为 2.048V 内部基准换算成微伏是整数避免浮点误差。放大处理是在除法时直接按增益档位缩放的逻辑上等效于先乘后除但不溢出。这个函数实测在从 -2048 到 2047 的满码值范围内都不会溢出32 位整数足够。5. ADS1110 驱动开发中的高频问题排查地址、数据对齐与时钟三个重灾区5.1 现象总线扫描能发现设备但读写返回垃圾值有次在某数据采集项目里扫描函数能看到 0x48 地址但读回来的原始码值一直在 0xFFFF 和 0x0000 之间疯跳偶尔还冒出来 0x7FFF。原因分析后发现是数据对齐处理出了问题。ADS1110 的 12 位数据在 16 位寄存器里左对齐低 4 位恒为 0。如果程序直接把buf[0] 8 | buf[1]当作 16 位结果把低 4 位零也算进有效位再除以 16 会得到正确结果如果某段代码里漏了右移 4 位看起来范围是 0 到 65520但这其实不对因为低 4 位不是有效数字。解决方式统一在驱动入口处处理所有读取函数都返回右移 4 位后的有符号 12 位值上层只要调ads1110_raw_to_uv()即可。从那以后我在新项目中都要求在头文件里写清楚返回值的单位是码值还是电压避免不同模块各写一套换算。5.2 现象改地址之后设备返回 NACK逻辑分析仪显示地址字节是 0x92某个模拟项目里想把两片 ADS1110 挂在一起按照手册把第二片芯片的 A0 引脚接 VCC地址理论是 0x49。代码里传入0x49 1作为 HAL 库地址参数结果设备完全不响应。定位这个问题时用逻辑分析仪抓了总线波形发现主机发出的地址字节是 0x92正好是 0x49 左移一位。HAL 库的 7 位地址模式要求传入的是不带读写位的 7 位地址即0x49 1而不是0x49 1。0x49 左移一位等于 0x92这个值作为 7 位地址超出范围了而且与 0x48 的映射也乱了。解决方式是查阅你所用的 I²C 库的地址位宽约定HAL 库用 7 位地址树莓派的smbus库用 8 位地址。统一做法是在驱动初始化函数里增加注释写明传入的是 7 位还是 8 位形式。5.3 现象差分输入时读数始终为负半幅或零接 PT100 电桥时发现读数稳定在负满量程附近但用万用表量差分电压明明是正的小电压。原因是 IN- 和 IN 接反了。ADS1110 的差分测量约定是 IN 减去 IN- 输出码值信号从电桥出来时如果公共地接法不对正负关系就反了。这时候软件上可以做一个交换逻辑但最稳的解法是硬件上把电桥的两根输出线对调。如果信号源是浮空的传感器还要注意共模电压不能超出芯片的输入范围否则即使差分电压正常共模部分也会把输入级顶到饱和。另一个容易忽略的点是上电时输入引脚悬空。差分输入端悬空时内部偏置电流会把输入电压拉到不确定电位读数表现为无规律跳动。解决方法是把 IN- 和 IN 各自通过 10kΩ 电阻拉到 GND让输入级有一个确定的偏置点。5.4 现象连续多次读取时数据偶尔跳变一个很大的值在监控面板上看到电压值偶尔从 1.234V 跳到 0.987V过几秒又跳回来幅度大约 20%。用示波器量输入电压是稳定的问题出在读取时序上。查了手册里的应用说明ADS1110 在连续转换模式下每次数据更新时输出寄存器会先写高字节再写低字节。如果主机正好在更新过程中发起读取可能读到的组合是上一次的高字节和下一次的低字节拼接出来的数据就变成了一个不存在的中间值。解决方法是判断数据就绪标志或者连续读两次丢弃第一次结果。连续读两次的方式更省事因为第一次读操作会把寄存器锁存到一个缓冲第二次读到的必定是同一帧数据的完整两个字节。我一般会在驱动里加一个ads1110_read_raw_stable()函数内部调用两次ads1110_read_raw()返回第二次的结果。5.5 现象I²C 总线 SDA 线被拉死所有 I²C 设备都失联一根总线上挂了 ADS1110、温度传感器和 EEPROM某次程序跑飞后 SDA 线一直保持低电平扫描和通信全部失败。I²C 协议里如果主机在通信中途异常复位从机可能还在等待后续时钟把 SDA 保持在发送状态。解决方式是让主机产生 9 个以上的时钟脉冲把从机状态机复位。很多 HAL 库的HAL_I2C_Init()不做这个总线恢复操作需要自己用 GPIO 模拟// 软件复位 I2C 总线产生 9 个时钟脉冲 void i2c_bus_recovery(GPIO_TypeDef *port_scl, uint16_t pin_scl, GPIO_TypeDef *port_sda, uint16_t pin_sda) { HAL_GPIO_WritePin(port_scl, pin_scl, GPIO_PIN_RESET); for (int i 0; i 9; i) { HAL_GPIO_WritePin(port_scl, pin_scl, GPIO_PIN_SET); HAL_Delay(1); HAL_GPIO_WritePin(port_scl, pin_scl, GPIO_PIN_RESET); HAL_Delay(1); } // 最后产生一个 STOP 条件 HAL_GPIO_WritePin(port_sda, pin_sda, GPIO_PIN_SET); HAL_GPIO_WritePin(port_scl, pin_scl, GPIO_PIN_SET); }这段恢复代码的本质是让总线上的从机接收到足够的时钟边沿强制它们退出正在传输的状态。注意在走恢复流程时要先把 SDA 释放为高电平否则后面产生的 STOP 条件不成立。6. 精度验证与差分测量技巧用零点校准和跨零点数据把 12 位用出 14 位的效果如果你已经能稳定读码值了下一步就是验证精度边界。我拿到新板子第一件事不是上传感器而是把 IN 和 IN- 短接在一起读 100 次原始码值。这个操作能暴露三个问题失调电压有多大、噪声分布范围是多少、有没有周期性干扰。短接读数的平均值如果偏离 0 超过 ±3 个 LSB说明芯片本身有可观失调如果 100 次读数跳动的范围超过 ±4 个 LSB说明布局或电源去耦有问题。这时候在 VDD 引脚旁边补一个 0.1μF 陶瓷电容通常能把跳动范围压缩一半。零点校准是精度提升最划算的手段。把短接读数存成offset_raw之后每次实际测量都先用原始码值减去这个偏移再换算。这样能把芯片本身的失调误差从 ±2 LSB 压低到接近 0。在控温项目里我用这个方法把温度采样误差从 ±0.5℃ 降到了 ±0.1℃ 以内。差分测量还有个容易忽略的技巧信号源如果参考地和 ADC 的 GND 有电位差差分输入也救不了。ADS1110 的 IN 和 IN- 虽然算的是差值但两个引脚对 GND 的电压必须落在电源范围内。测量浮空电池电压时要把电池负极与 ADS1110 的 GND 相连形成共地参考。对传感器信号来说12 位分辨率有一个隐形的使用边界信号幅度必须尽量占满 PGA 量程。同样一个 0-100mV 的信号用 8 倍增益时码值分布在 ±1600 附近量化分辨率等效出来约等于 14 位 ADC 在 0-100mV 满量程下的表现。这个逻辑反过来也成立——如果信号本身只有 2mV8 倍增益下也只有 16mV 量程的 1/8这时候该考虑外置放大或者换更高位数的 ADC。最后一个技巧是采样率的取舍。ADS1110 支持的最高速率是 15SPS 和 30SPS 两档但实际噪声水平会随速率上升而变差。我习惯在信号本身变化慢的场景里用 15SPS然后在软件里做 4 次平均等效采样率变成约 3.75SPS但噪声峰值能压低一半左右。这套组合在测温度和压力这类缓变信号上表现相当稳。以前我每次拿到新 ADC 第一反应都是先写驱动再对着手册查寄存器位后来发现顺序要反过来先拿万用表确认参考电压的稳定性再确认地址映射关系最后动代码可以少走不少弯路。从那以后我每次焊完板子都会强制走一遍短接读数、零点校准、地址扫描这个流程。希望这些经验能在你调 ADS1110 时派上用场。本文还有配套的精品资源点击获取