Arduino 板载 ADC 只有 10 位,Uno 上 A0 读出来是 0-1023,一格就是约 4.9mV。想测一个几十毫伏的小信号——电桥输出、微弱压差——这个分辨率直接不够用。TI 的 ADS1115 是这类问题的标准解法之一:16 位输出、I2C 接口、四路输入还自带可编程增益,官方标称最高 860SPS。这篇把它接到 Arduino 上,从接线到四通道单端、差分读取、增益设置,一次走完。

模块速览:先把数字摆出来
ADS1115 是 TI 的 16 位 delta-sigma ADC,官方产品页给的关键参数很齐:供电 2.0V 到 5.5V,连续转换模式下功耗 150µA,数据率 8SPS 到 860SPS 可编程,PGA 输入量程 ±256mV 到 ±6.144V,内置基准源和振荡器,I2C 接口有四个可选地址,工作温度 -40°C 到 +125°C。输入端可以配成四路单端,也可以配成两路差分。
Adafruit 的 STEMMA QT 版转接板把这块芯片做成了即插即用的小板,2V 到 5V 的电源和逻辑电平都能直接吃,3.3V 和 5V 主控通吃。同一根 I2C 总线最多挂 4 块板,单端 16 通道或者差分 8 通道。这款转接板在 Adafruit 官方商城标价 14.95 美元(截至11月10日);同板的 ADS1015 版本 12 位、3300SPS,标价 9.95 美元。两者只差分辨率和速度,其余玩法一样。
| 参数 | ADS1115 | ADS1015 |
|---|---|---|
| 分辨率 | 16 位 | 12 位 |
| 最高数据率 | 860SPS | 3300SPS |
| 输入通道 | 4 单端 / 2 差分 | 4 单端 / 2 差分 |
| PGA 量程 | ±256mV 至 ±6.144V | ±256mV 至 ±6.144V |
| 供电范围 | 2.0V 至 5.5V | 2.0V 至 5.5V |

接线:四根线搞定
接线非常省事。5V 主控(Uno、Metro 这类)用 5V 接 VIN;3.3V 主控(Feather 这类)就接 3.3V。剩下三根:SCL 接 SCL,SDA 接 SDA,GND 接 GND。板子带 STEMMA QT / Qwiic 插口的话,一根 JST 线直插,连杜邦线都省了。

模块上还有一个 ADDR 引脚,用来改 I2C 地址:接 GND 是 0x48(默认),接 VDD 是 0x49,接 SDA 是 0x4A,接 SCL 是 0x4B。悬空时 Adafruit 板子的默认地址是 0x48。想在一根总线上多挂几块板,就把不同板的 ADDR 接到不同位置,配成 0x48 到 0x4B 四个地址。
如果要测真正的差分信号,比如电桥的两个输出端,把它们分别接 AIN0 和 AIN1 就行。普通传感器输出则走单端:传感器输出接 AIN0 到 AIN3 任意一路,共地即可。

装库与四通道单端读数
库用 Adafruit 官方的 Adafruit_ADS1X15,在 Arduino IDE 的库管理器里搜 ADS1X15 安装即可。下面这段四通道单端读取的示例照官方教程页原样搬来。说明一点:站点正文会剥掉尖括号头文件,所以 #include 和 #include 在这里按编译等价写法换成双引号形式,两种写法对库搜索路径等价,其余字符一字未动。
#include "Wire.h"
#include "Adafruit_ADS1X15.h"
Adafruit_ADS1015 ads1015; // Construct an ads1015
void setup(void)
{
Serial.begin(9600);
Serial.println("Hello!");
Serial.println("Getting single-ended readings from AIN0..3");
Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV)");
ads1015.begin();
}
void loop(void)
{
int16_t adc0, adc1, adc2, adc3;
adc0 = ads1015.readADC_SingleEnded(0);
adc1 = ads1015.readADC_SingleEnded(1);
adc2 = ads1015.readADC_SingleEnded(2);
adc3 = ads1015.readADC_SingleEnded(3);
Serial.print("AIN0: "); Serial.println(adc0);
Serial.print("AIN1: "); Serial.println(adc1);
Serial.print("AIN2: "); Serial.println(adc2);
Serial.print("AIN3: "); Serial.println(adc3);
Serial.println(" ");
delay(1000);
}
注意官方示例代码是按 ADS1015 写的,量程注释里的 3mV 一格也是 12 位版的换算。换成 ADS1115 时,把对象改成 Adafruit_ADS1115 ads1115;、调用 ads1115.begin(),换算系数相应变成 0.1875mV 一格(官方教程页给的口径是约 188µV/bit),原始读数范围变成 16 位的整数。readADC_SingleEnded 括号里的 0 到 3 就对应 AIN0 到 AIN3 四路输入。
库也支持在 begin 时直接传地址:手头板子把 ADDR 接了 VDD,就写 ads1115.begin(0x49),这个写法官方示例里同样有。
差分模式:读两点的电压差
差分是这块芯片对小白最值钱的功能。单端读的是某一路对地的电压,而差分读的是两路之间的电压差,共模干扰、地电位漂移在很大程度上被抵掉,小信号干净得多。ADS1115 提供两组差分对:AIN0 对 AIN1、AIN2 对 AIN3。官方差分示例原样如下:
#include "Wire.h"
#include "Adafruit_ADS1X15.h"
Adafruit_ADS1015 ads1015;
void setup(void)
{
Serial.begin(9600);
Serial.println("Hello!");
Serial.println("Getting differential reading from AIN0 (P) and AIN1 (N)");
Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV)");
ads1015.begin();
}
void loop(void)
{
int16_t results;
results = ads1015.readADC_Differential_0_1();
Serial.print("Differential: "); Serial.print(results); Serial.print("("); Serial.print(results * 3); Serial.println("mV)");
delay(1000);
}
readADC_Differential_0_1() 返回的是 int16_t 有符号数:AIN0 电位高于 AIN1 时是正值,反过来就是负值,这一点和单端的 0 起步完全不同,解析读数时要留意符号。示例里 results * 3 把原始值换算成毫伏,同样是 ADS1015 口径;ADS1115 上把这个乘数换成 0.1875 才是毫伏值,函数名换成 ads1115.readADC_Differential_0_1() 即可,AIN2 对 AIN3 那组对应的是 readADC_Differential_2_3()。
增益设置:把小信号放大了读
PGA 是这块芯片的另一半价值。量程默认 ±6.144V,一格 0.1875mV;信号本身只有几百毫伏时,缩窄量程等效于放大输入,分辨率利用率直线上升。六档增益对应关系官方代码注释里列得明明白白:
ads1015.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV (default)
// ads1015.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV
// ads1015.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV
// ads1015.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV
// ads1015.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV
// ads1015.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV
选档思路很简单:信号峰值是多少,就选一个比它大一点的量程。比如传感器输出 1V 上下,官方示例给的就是 GAIN_FOUR(±1.024V 档)。对 ADS1115 来说,每档的量程和上面完全相同,但一格代表的电压是 ADS1015 的十六分之一:±6.144V 档一格 0.1875mV,依次除以 2,到 ±0.256V 档一格约 0.0078mV。0.0078mV 换个说法就是接近 8µV 一格,这才是 16 位 ADC 的真正牌面。
两处细节别踩。其一,增益会改变原始读数但不改变电压本身——同一个 0.168V 的信号,增益 1 倍时原始值 84,增益 16 倍时变成 1335 左右,官方教程用这组实测数演示过这层关系,最终换算回电压都是 0.168V 附近。其二,量程必须罩得住信号:把 2V 的信号塞进 ±0.256V 档,读数直接顶满饱和,不是坏事但数据没法用。
库还留了 getGain() 读当前增益、getLastConversionResults() 取最近一次转换结果,以及比较器模式——超过阈值就在 ALRT 引脚上拉信号,可以轮询也可以当中断用。想做的通道守门场景(比如某路电压越限就报警),不用主循环反复读,比较器是更省 CPU 的做法。
写在最后
从数据角度看,ADS1115 的性价比逻辑很清楚:十几美元一块板,换来 16 位分辨率、六档 PGA、四路可复用输入和一个硬件比较器,四块板还能并到同一根 I2C 总线上扩到 16 个单端通道。Arduino 板载 ADC 处理不了的毫伏级信号,它接手后一格能细到几微伏。唯一要适应的是示例代码里 ADS1015 与 ADS1115 的换算系数差异——3mV 与 0.1875mV 一字之差,算错就是 16 倍的偏差,接线对了数据不对时先查这个。











STEMMA QT 插口是真省心,一根线接完就能用
刚入门想问下,四块板挂同一根总线的话,地址是不是只能用 0x48 到 0x4B 这四个?再多就得换别的方案了吧
接线图比代码看着踏实,先收藏了
之前用 Uno 板载 ADC 测过应变片电桥,输出才二十几毫伏,读数跳得没法看,后来才明白 10 位 ADC 一格 4.9mV,信号直接淹在分辨率里。换成 ADS1115 把增益拉到 16 倍档,量程 ±0.256V,一格不到 8µV,曲线立刻稳定了。差分接法把两根线共模的漂移抵掉这点确实值,文章里 int16_t 有符号那个提醒也很关键,我第一次接反极性时还以为是模块坏了。