在电子制作和电路调试过程中,电压测量是最基础也最频繁的操作之一。虽然万用表可以满足基本需求,但当我们需要同时监测多个测试点、记录电压变化趋势或测量微小电压差时,传统工具就显得力不从心。本文将带你用Arduino UNO开发板和ADS1115模数转换模块,打造一个功能强大的多通道电压监测系统,不仅能同时测量四个独立通道的电压,还能处理正负电压信号,精度远超普通万用表。
这个项目的独特价值在于它的灵活性和扩展性。通过编程配置,你可以自定义测量范围(从±256mV到±6.144V)、采样速率(8-860次/秒),并选择单端或差分测量模式。最终成果可以作为一个独立的电压表使用,也可以集成到更大的项目中作为数据采集模块。无论是电源质量监测、传感器信号分析还是实验数据记录,这个DIY工具都能大显身手。
ADS1115是德州仪器(TI)推出的一款16位精度模数转换器(ADC),相比Arduino UNO内置的10位ADC,它的分辨率提高了64倍。这意味着在相同的电压范围内,ADS1115能够检测到更微小的电压变化——对于测量传感器信号或微小电压差至关重要。
模块的核心特性包括:
提示:ADS1115的PGA功能特别实用,它能自动放大微小信号,无需外接放大电路即可直接测量热电偶、称重传感器等输出的毫伏级信号。
虽然市面上有更强大的开发板,但Arduino UNO仍然是此类项目的理想选择:
要完成本项目,你需要准备以下组件:
| 组件 | 规格 | 数量 | 备注 |
|---|---|---|---|
| Arduino UNO | R3版本 | 1 | 或其他兼容板 |
| ADS1115模块 | 16位ADC | 1 | 带板载电压基准 |
| 面包板 | 830孔 | 1 | 用于原型搭建 |
| 杜邦线 | 公对公 | 若干 | 建议不同颜色 |
| 液晶屏 | I2C接口1602 | 1 | 可选,用于显示 |
| 电阻 | 10kΩ | 4 | 分压用,可选 |
| 电位器 | 10kΩ | 1 | 测试信号源 |
ADS1115与Arduino UNO的连接非常简单,只需要4根线:
arduino复制// ADS1115引脚定义
#define ADS1115_ADDR 0x48 // 默认I2C地址
// Arduino UNO连接方式:
// ADS1115 VCC → Arduino 5V
// ADS1115 GND → Arduino GND
// ADS1115 SCL → Arduino A5(SCL)
// ADS1115 SDA → Arduino A4(SDA)
实际接线时,建议使用不同颜色的杜邦线区分电源和信号线,例如红色接5V,黑色接GND,黄色接SCL,绿色接SDA。这种标准化配色方案能显著降低接错线的风险。
ADS1115支持两种基本测量模式:
单端输入模式:
差分输入模式:
模式选择不仅影响接线方式,也关系到量程设置。例如,当测量±5V信号时,在单端模式下需要选择±6.144V量程,因为每个引脚电压都是相对于GND的正值;而在差分模式下,可以选择±4.096V量程,因为实际电压差通常较小。
为了提升系统的实用性,可以考虑添加以下电路:
电压分压网络:用电阻分压测量高于6.144V的电压
text复制待测高压 → [R1] → ADC输入 → [R2] → GND
分压比计算公式:Vadc = Vinput × R2/(R1+R2)
信号调理电路:对于含有噪声的信号,可以添加RC低通滤波
text复制信号输入 → [10kΩ] → ADC输入
↓
[0.1μF] → GND
过压保护:在ADC输入端串联1kΩ电阻并并联5.1V稳压管,防止意外高压损坏芯片
首先需要安装ADS1115的驱动库。在Arduino IDE中,可以通过库管理器搜索并安装"Adafruit ADS1X15"库,这是一个被广泛使用的优质库。
arduino复制#include <Wire.h>
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1115 ads; // 创建ADS1115实例
void setup() {
Serial.begin(9600);
if (!ads.begin(0x48)) { // 初始化I2C通信
Serial.println("Failed to initialize ADS1115!");
while (1);
}
// 设置增益和量程 (±6.144V)
ads.setGain(GAIN_TWOTHIRDS);
}
最基本的单端电压测量代码如下:
arduino复制void loop() {
int16_t adc0 = ads.readADC_SingleEnded(0); // 读取A0通道
float voltage = ads.computeVolts(adc0); // 转换为电压值
Serial.print("A0 Voltage: ");
Serial.print(voltage, 4); // 显示4位小数
Serial.println("V");
delay(500); // 半秒更新一次
}
要充分利用ADS1115的多通道能力,可以实现循环扫描:
arduino复制void readAllChannels() {
for (int ch = 0; ch < 4; ch++) {
int16_t adc = ads.readADC_SingleEnded(ch);
float volts = ads.computeVolts(adc);
Serial.print("A"); Serial.print(ch);
Serial.print(": "); Serial.print(volts, 4);
Serial.print("V\t");
}
Serial.println();
}
差分测量则需要稍作修改:
arduino复制int16_t diff_0_1 = ads.readADC_Differential_0_1();
float diffVoltage = ads.computeVolts(diff_0_1);
ADS1115允许调整采样率以平衡速度和精度:
arduino复制// 在setup()中添加:
ads.setDataRate(RATE_ADS1115_860SPS); // 最高860次/秒
// 可选速率:
// RATE_ADS1115_8SPS (8次/秒)
// RATE_ADS1115_16SPS (16次/秒)
// ...
// RATE_ADS1115_860SPS (860次/秒)
高采样率适合捕捉快速变化的信号,但会略微降低分辨率。对于静态或慢变信号,建议使用较低的采样率以获得更好的噪声性能。
为了摆脱对电脑串口监视器的依赖,可以添加I2C接口的LCD显示屏:
arduino复制#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // 地址可能为0x3F
void setup() {
lcd.init();
lcd.backlight();
}
void displayVoltage(int channel, float voltage) {
lcd.setCursor(0, 0);
lcd.print("CH"); lcd.print(channel);
lcd.print(":");
lcd.print(voltage, 3);
lcd.print("V ");
}
将电压数据记录到SD卡或发送到电脑进行可视化分析:
arduino复制#include <SD.h>
void logData(float v0, float v1, float v2, float v3) {
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile) {
dataFile.print(millis()); dataFile.print(",");
dataFile.print(v0, 4); dataFile.print(",");
dataFile.print(v1, 4); dataFile.print(",");
dataFile.print(v2, 4); dataFile.print(",");
dataFile.println(v3, 4);
dataFile.close();
}
}
利用ADS1115内置的比较器,可以实现硬件级的阈值检测:
arduino复制// 设置阈值触发
ads.setComparatorQueEnable(false); // 禁用队列
ads.setComparatorLatchEnable(true); // 启用锁存
ads.setComparatorPolarityLow(); // 低电平有效
ads.setComparatorModeTraditional(); // 传统比较模式
// 设置高低阈值 (以ADC计数值表示)
ads.setLowThreshold(-1000);
ads.setHighThreshold(1000);
// 在循环中检查警报
if (ads.getLastConversionResults() >= ads.getHighThreshold()) {
digitalWrite(BUZZER_PIN, HIGH); // 触发蜂鸣器
}
用分压电阻测量多节锂电池串联的总电压:
arduino复制// 假设使用100kΩ和10kΩ分压电阻
const float R1 = 100000.0;
const float R2 = 10000.0;
const float DIVIDER_RATIO = (R1 + R2) / R2;
float readBatteryVoltage(int channel) {
int16_t adc = ads.readADC_SingleEnded(channel);
float voltage = ads.computeVolts(adc) * DIVIDER_RATIO;
return voltage;
}
配合分流电阻测量电流:
text复制// 接线示例:
// 电源+ → 负载+ → 负载- → [分流电阻] → 电源-
// ADS1115 A0接分流电阻左侧,A1接右侧
计算电流的代码:
arduino复制const float SHUNT_RESISTOR = 0.1; // 0.1欧姆分流电阻
float readCurrent() {
int16_t diff = ads.readADC_Differential_0_1();
float voltage = ads.computeVolts(diff);
float current = voltage / SHUNT_RESISTOR;
return current; // 单位:安培
}
通过测量热电偶或热敏电阻电压来监测温度:
arduino复制// NTC热敏电阻温度计算
const float BETA = 3950.0; // B值
const float R25 = 10000.0; // 25℃时的电阻值
const float R_REF = 10000.0; // 分压参考电阻
float readTemperature(int channel) {
int16_t adc = ads.readADC_SingleEnded(channel);
float Vout = ads.computeVolts(adc);
float Rntc = R_REF * (3.3 / Vout - 1.0);
// Steinhart-Hart方程
float steinhart = log(Rntc / R25) / BETA + 1.0 / (25.0 + 273.15);
float tempK = 1.0 / steinhart;
float tempC = tempK - 273.15;
return tempC;
}
为提高测量精度,可以进行简单的两点校准:
arduino复制// 校准参数
float gain_error = 1.012; // 增益误差修正
float offset_error = 0.003; // 零点偏移修正(V)
float calibratedRead(int channel) {
int16_t raw = ads.readADC_SingleEnded(channel);
float voltage = ads.computeVolts(raw);
return (voltage - offset_error) * gain_error;
}
校准步骤: