资讯动态

ADS1110驱动开发:I2C地址配置与寄存器详解

发布时间:2026/9/10 2:47:20 来源:尧图企业网站定制
简介针对ADS1110高精度12位ADC的嵌入式开发需求这份资料集驱动源码与中文技术手册于一体适合单片机、Arduino、树莓派等I2C应用开发者。资源内ADS1110.doc详细说明技术规格、寄存器配置、增益与采样率设置、应用电路等ads1110.c提供初始化、读取、写入等接口函数并支持通过A0-A2引脚修改器件地址便于多设备挂接同一I2C总线。压缩包共2个文件以文档和C源码为主整体约199KB小巧易用。目前已有863人学习下载对需要快速上手ADS1110、规避通信时序坑点的开发者有直接参考价值。1. 从“ADS1110驱动与中文手册”说起一块低调的16位ADCADS1110是TI出品的一款单通道16位Δ-Σ型ADCI2C接口内部自带2.048V基准电压和可编程增益放大器PGA非常适合称重传感器、热电偶、电池电压等低速高分辨率测量场景。不少工程师第一次接触它都是先下载一个名为“ADS1110驱动与中文手册.rar”的资源包结果发现里面代码风格各异中文手册翻译生涩最要命的是“改地址”这个操作在手册里根本找不到。这篇文章不绕弯子直接从数据手册最关键的引脚、寄存器表和时序讲起给出一套能在裸机I2C和Linux用户态下跑通的驱动写法再专门把“改地址”这个最大的认知误区讲透。适合正在调I2C总线、需要快速出数据的嵌入式开发者也适合刚接手ADS1110项目、想少走弯路的硬件工程师。2. ADS1110的硬件根基引脚、寄存器与地址编码2.1 引脚与最小系统别把VDD和VREF搞混ADS1110采用6引脚SOT-23封装引脚依次为VDD、GND、IN、IN-、SDA、SCL。它没有独立的VREF引脚也没有AGND/AVDD之分所有模拟输入都是相对于GND的单端-差分混合方式IN和IN-是真正的差分输入信号电压落在内部ADC核心的差分输入端。这里最容易犯的错是把VDD当作基准电压实际上ADS1110内部基准固定在2.048V与电源电压无关。VDD可以在2.7V到5.5V之间比如3.3V供电时满量程仍然是±2.048V增益为1时而不是±3.3V。最小系统很简单VDD和GND之间加0.1μF陶瓷电容去耦位置尽量靠近引脚SDA和SCL各接一个上拉电阻到VDD阻值常用4.7kΩIN和IN-分别接被测信号的正确端和负端。如果信号源内阻较大可以在输入前加一级RC低通滤波比如100Ω电阻和1μF电容截止频率约1.6kHz能有效滤除高频噪声。SDA、SCL上拉电阻的选择要留意I2C速度100kHz标准模式可用4.7kΩ400kHz快速模式建议用2.2kΩ否则上升沿太慢会导致通信异常。2.2 配置寄存器一位一位读ST、DR、PGAADS1110的配置寄存器只有一个字节地址固定在器件内部不是通过I2C子地址访问的。这个字节各位定义如下表所示。写驱动前先把这张表抄在纸上后面所有配置都是围绕它展开的。位名称功能默认值7ST1启动单次转换0连续转换模式16-5DR[1:0]数据速率0015SPS0130SPS1060SPS11240SPS004-3PGA[1:0]增益001012104118002-0—保留位必须写0000上电后默认配置值为0x8C二进制10001100也就是ST1、15SPS、增益1、保留位为0。此时芯片处于单次转换模式但并没有自动开始转换需要主机写入一个配置字节后才会启动。一个常见的初始化写法是直接写0x8C但要注意这个操作既设置了模式又触发了转换。如果之后没有延时等待转换完成就读取读到的数据可能是上一次的旧值或者无效值。如果需要连续输出则写入0x0C芯片会以15SPS的速率持续转换每次读取都能拿到最新结果无需额外触发。2.3 地址字节的真相硬地址与软地址如何拼出8位从机地址ADS1110的从机地址固定为二进制1001000即0x48。它不像ADS1115那样有一个ADDR引脚通过接VDD、GND、SDA或SCL来选择四个地址ADS1110的封装里根本没有地址引脚。这是“改地址”问题的最原始冲突点很多在ADS1115或ADS1112上验证过的“改地址”方法照搬到ADS1110上必然失败。在I2C协议层7位地址0x48经过移位后形成8位地址读地址为0x910x481 | 1写地址为0x900x481 | 0。不同平台的驱动代码写法不一样裸机I2C控制器通常要求你传入8位地址Linux内核的I2C框架使用7位地址0x48i2c-dev用户态接口也填0x48而STM32 HAL库则传入左移后的0x90或0x91。理解这个差异排查No Ack错误时能省一半时间。3. 写驱动前必须搞定的时序与协议细节3.1 I2C起始、停止与应答问题为什么读不到数据ADS1110是纯I2C从机支持标准模式100kHz和快速模式400kHz。它对起始条件、停止条件和ACK时序的要求与普通I2C器件一致但有一个容易踩坑的地方主机发起读操作时如果芯片正在内部转换它可能不拉低SCL等待而是直接不响应ACK导致read()返回错误。解决办法不是加大超时而是调整读取策略——在连续转换模式下确保两次读取间隔大于一个转换周期在单次转换模式下先写配置再延时然后再读。建议用逻辑分析仪抓一次波形重点看ACK位。如果SDA在第9个时钟周期保持高电平说明从机没应答原因通常是地址错误或器件未上电。另一种常见情况是总线上有其他器件应答了因为地址冲突比如另一片ADS1110也在0x48这时数据会错乱但ACK正常稍后改地址章节会专门处理。3.2 读转换结果16位数据的极性处理ADS1110的转换结果是16位二进制补码最高位为符号位。读取时一次I2C读操作可以拿回3个字节第一个字节是转换结果的高8位第二个是低8位第三个是当前配置寄存器值。驱动里最关键的代码就是合成有符号数uint8_t buf[3]; int16_t raw; /* 发起读操作要求从机连续返回3字节 */ read(fd, buf, 3); raw (int16_t)(((uint16_t)buf[0] 8) | buf[1]);这里必须先把buf[0]强转为无符号16位后再左移否则buf[0]的符号位会被扩展到高16位最后结果变成全0或者错误的负数。合成后的raw范围是-32768~32767。对应电压计算公式为double voltage raw / 32768.0 * (2.048 / pga);PGA为增益值1、2、4、8。当PGA1时一个LSB对应62.5μVPGA8时一个LSB对应7.8125μV。注意输入电压不能超过2.048V除以PGA否则输出饱和到满量程且不会产生溢出标志这一点与带溢出标志的ADC不同需要自行判断。3.3 写配置寄存器一次性写入别用读改写ADS1110的配置寄存器不支持子地址寻址主机直接向从机地址写入一个字节即可完成配置。由于保留位必须为0不需要先读回再修改某一位直接拼出完整字节写入即可。例如要设置30SPS、增益2则ST0、DR01、PGA01、保留位000算出0x24。连续转换模式下写入后芯片立刻开始按新配置转换。写入后要等多久才能读到有效数据可以用下面的经验时间表也可以直接读回第三字节确认ST位状态在单次转换模式下ST位会在转换完成后自动清0轮询这个位可以精确判断数据就绪比盲目延时更可靠。数据速率SPS最快转换时间ms建议延时ms1566.7703033.3356016.7182404.253.4 一个可用的ADS1110驱动框架C语言下面是一个面向Linux i2c-dev的驱动框架使用通用的open/read/write接口。把硬件I2C适配器编号作为参数传入例如/dev/i2c-1。#include stdio.h #include stdint.h #include unistd.h #include fcntl.h #include sys/ioctl.h #include linux/i2c-dev.h #define ADS1110_ADDR 0x48 #define ADS1110_CFG_CONT 0x0C /* 连续转换 15SPS PGA1 */ #define ADS1110_CFG_SINGLE 0x8C /* 单次触发 15SPS PGA1 */ static int ads1110_write_config(int fd, uint8_t cfg) { if (ioctl(fd, I2C_SLAVE, ADS1110_ADDR) 0) { perror(I2C_SLAVE); return -1; } if (write(fd, cfg, 1) ! 1) { perror(write config); return -1; } return 0; } static int ads1110_read_raw(int fd, int16_t *raw) { uint8_t buf[3]; if (read(fd, buf, 3) ! 3) { perror(read adc); return -1; } *raw (int16_t)(((uint16_t)buf[0] 8) | buf[1]); return 0; } double ads1110_read_voltage(int fd, double pga) { int16_t raw; if (ads1110_read_raw(fd, raw) 0) { return -1.0; } return raw * (2.048 / (pga * 32768.0)); }代码里write_config先设置I2C从机地址再发送一个字节的配置。read_raw直接读取3个字节丢弃第三个配置字节也可以用来校验。ads1110_read_voltage把转换结果换算成电压。连续转换模式下主循环里每次读取前都不需要重新写配置但要注意读取间隔必须大于当前SPS对应的转换周期否则连续两次读到的可能是同一份数据。4. 实战驱动从裸机到Linux用户态4.1 STM32 HAL库下的ADS1110驱动关键代码在STM32上使用HAL库驱动ADS1110本质就是I2C的收发操作。要注意HAL库的地址参数是8位从机地址即7位地址左移一位。连续转换模式下初始化一次配置即可之后直接接收3字节/* 初始化配置 */ uint8_t cfg 0x0C; /* 15SPS, PGA1, 连续转换 */ HAL_I2C_Master_Transmit(hi2c1, (0x48 1), cfg, 1, HAL_MAX_DELAY); /* 读取数据 */ uint8_t buf[3]; HAL_I2C_Master_Receive(hi2c1, (0x48 1), buf, 3, HAL_MAX_DELAY); int16_t raw (int16_t)(((uint16_t)buf[0] 8) | buf[1]); float voltage raw * (2.048f / 32768.0f);单次转换模式则要先发送0x8C启动转换然后延时70ms再接收数据。接收时最好先调用HAL_I2C_IsDeviceReady确认总线正常如果返回HAL_BUSY说明I2C总线被其他设备卡住需要做总线复位切换SCL时钟9次。STM32的HAL库在I2C错误后不会自动释放SDA因此建议在驱动里加一个错误恢复函数把SCL拉到低电平再翻转9个周期释放可能被锁住的从机。4.2 Linux用户态通过i2c-dev直接访问树莓派、飞腾派或各种ARM开发板上跑Linux最快速的验证方法是使用i2c-tools。先扫描总线确认设备地址i2cdetect -y 1输出中会在0x48位置显示设备编号如果此处显示“UU”表示地址被内核驱动占用需要先卸载对应驱动。确认地址后用i2ctransfer直接读写适合快速验证波形和配置# 写入配置连续转换 15SPS PGA1 i2ctransfer -y 1 w10x48 0x0C # 读取3字节高字节、低字节、配置寄存器 i2ctransfer -y 1 r30x48第二条命令输出的三个十六进制数中前两个拼成16位有符号数第三个配置字节应该是0x0C。若读到的配置字节是0x8C说明芯片仍处于单次转换模式可能是因为上电后没有写入配置。这种命令行验证方式比写C代码更直观适合在写正式驱动前确认硬件连接没有问题。4.3 与中文手册对应的寄存器校验流程很多中文手册会把“读配置寄存器”这一步漏掉导致驱动写完但不知道芯片工作在什么状态。我建议在驱动的初始化函数里加一段自检读取3字节后比较第三个字节与写入的配置值是否一致。如果不一致优先检查I2C地址是否正确其次检查写操作是否被NACK。下面这段伪代码展示了校验逻辑int ads1110_self_check(int fd) { uint8_t cfg 0x0C; uint8_t buf[3]; if (ads1110_write_config(fd, cfg) 0) return -1; usleep(20000); if (read(fd, buf, 3) ! 3) return -1; if (buf[2] ! cfg) { fprintf(stderr, config mismatch: expect 0x%02X, got 0x%02X\n, cfg, buf[2]); return -1; } return 0; }注意读操作之前要清掉I2C_RDWR等ioctl状态确保fd没有残留阻塞标志。自检通过后再进入正常的数据读取循环。5. 改地址一个电阻决定的总线命运5.1 为什么ADS1110无法像ADS1115那样改地址ADS1115的ADDR引脚允许通过接VDD、GND、SDA、SCL四种组合选择四个从机地址而ADS1110没有这个引脚地址是出厂固化的0x48。很多中文手册在“地址选择”章节里直接抄了ADS1115的内容误导了大批读者。如果你看到一本手册里写着“通过ADR0/ADR1引脚电平设定地址”请立即核对型号那大概率不是ADS1110的手册。既然硬件不能改那多片ADS1110共用一个I2C总线怎么办下面三个方案是在实际项目里最常用的替代路径按成本从高到低排列。5.2 方案一用I2C多路复用器把总线切开最可靠、最省心的方案是使用TCA9548A这类I2C多路复用器。TCA9548A本身是一个I2C从设备地址由3个硬件引脚设定常见为0x70。它把一条上游总线分成8条下游子总线每次只能选通其中一条。/* 选择通道0使下游子总线0与主总线连通 */ uint8_t channel 0x01; HAL_I2C_Master_Transmit(hi2c1, (0x70 1), channel, 1, HAL_MAX_DELAY);选通后主总线就能访问挂在通道0上的ADS1110地址仍为0x48。要读另一片时先切换到通道1再访问。注意切换通道后必须加至少100μs的延时等待下游器件总线稳定。这个方案可以做到最多8片ADS1110而且不影响原来总线上其他I2C设备是工程上最正规的做法。5.3 方案二每片单独供电的伪地址切换如果你不想加额外的芯片可以用GPIO控制每片ADS1110的VDD。读取某片之前先将其VDD置高等待10ms让内部基准和振荡器稳定然后进行I2C通信完成后把VDD拉低。未上电的芯片不会参与总线通信相当于实现了“地址切换”。void select_ads1110(int index) { for (int i 0; i N; i) { HAL_GPIO_WritePin(PWR_GPIO_Port, 1 i, (i index) ? GPIO_PIN_SET : GPIO_PIN_RESET); } HAL_Delay(10); }这个方法的坑在于未上电芯片的SDA/SCL引脚可能存在漏电路径把总线电平拉低。解决方法是给每片芯片的SDA、SCL串联一个1kΩ隔离电阻或者使用三态缓冲器。此方案适合静态测量场景比如几十秒采集一次不适合高频连续采样。5.4 方案三软件模拟I2C每个芯片独占一路SDA在单片机GPIO资源充足的情况下可以定义两路独立的软件I2C引脚各挂一片ADS1110。软件模拟I2C本来就能达到100kHz以上ADS1110的15SPS转换速率远低于通信速率时序压力很小。网上很多裸机驱动都是基于GPIO位翻转实现的核心就是起始条件时拉低SDA再拉低SCL停止条件时先拉高SCL再拉高SDA。这个方案的优势是完全避开地址问题缺点是占用GPIO多且代码可维护性较差。5.5 改地址后常见的三种错误第一地址参数填错。有人把0x48左移一位后得到0x90但误以为0x90就是7位地址导致在Linux里设置I2C_SLAVE为0x90失败。记住i2c-dev和内核I2C框架均使用7位地址0x48HAL库才需要左移。第二扫描时看到两片0x48以为总线冲突。实际上i2cdetect只能检测到ACK如果两片ADS1110都挂在同一条总线上扫描时只会显示一个0x48并不会报警但数据会互相串扰。所以扫描结果正常不代表多片共存没有问题。第三复用器切换后没有延时。TCA9548A的通道切换命令本身需要时间下游总线电容也会拖慢第一个ACK建议在每次切换后加1ms延时并调用HAL_I2C_IsDeviceReady确认芯片在线再开始数据传输。6. 验证驱动与读数的几个实用技巧6.1 用一颗基准源快速验证PGA和满量程驱动写好后先别急着接传感器。找一个精密稳压源比如REF3030作为输入接成IN到基准正极、IN-到GND。设置PGA1理论上应该读到约3010mV对应的数值。如果读数偏差超过0.1%优先怀疑上拉电阻和输入RC滤波。如果读数接近2.048V的满量程且在2.048V处饱和说明基准2.048V正常但输入电压超量程。此时把PGA调到8重新计算电压数值应该大约缩小8倍未超量程时。6.2 用统计方法确认噪声水平ADS1110手册给出的有效分辨率通常带参考条件实际板子上的噪声常比理想高。我一般会连续采集1000个点计算均值和标准差。计算公式为import statistics samples [0.5321, 0.5322, 0.5319, ...] mean statistics.mean(samples) std statistics.stdev(samples)以15SPS、PGA1、输入端短接ININ-为例良好布局下标准差应在几十μV以内大约等于1~2个LSB。如果标准差超过10个LSB检查电源纹波、I2C线上的数字噪声是否耦合到模拟输入以及是否用了面包板搭电路。6.3 与中文手册对照时最容易忽略的电气参数第一输入共模范围。ADS1110的IN-并不是真正的虚拟地输入共模电压必须在GND-0.2V到VDD0.2V之间否则转换结果会出现非线性。第二偏移误差与温漂手册指标通常给出典型值但实际器件可能到几十μV对于称重这类应用需要在软件里做零位校准。第三转换速率的漂移内部振荡器精度在±10%左右所以定时读取时不要依赖精确的SPS数值而是用读到的配置字节或内部事件节拍。最后保留位必须写0如果写入非零值芯片行为不可预期这也是校验配置寄存器最重要的原因。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价