1. ADS1115模数转换器与STC单片机组合概述
在嵌入式传感器数据采集领域,ADS1115作为一款16位精度的模数转换器(ADC),与STC系列单片机的组合堪称经典搭档。我曾在工业温控、便携式医疗设备等多个项目中采用这种方案,其优势在于以极低的成本实现高精度模拟信号采集。ADS1115的I²C接口与STC单片机完美兼容,单芯片即可处理4路差分或单端输入,内部可编程增益放大器(PGA)支持±6.144V到±0.256V的输入范围,特别适合传感器输出的微小信号放大。
这个组合最吸引工程师的特点在于:STC单片机通过简单的I²C协议就能驱动ADS1115,无需复杂的外围电路。实际项目中,我曾用STC15W4K系列驱动ADS1115采集PT100温度信号,在-20℃~100℃范围内实现了±0.1℃的测量精度。相比STC内置的10位ADC,ADS1115的16位分辨率将测量精度提升了64倍,而硬件成本仅增加约15元人民币。
2. 硬件系统设计与接口连接
2.1 最小系统搭建要点
ADS1115与STC单片机连接仅需4根线:VCC(2.0-5.5V)、GND、SCL、SDA。建议在VCC与GND间并联0.1μF去耦电容,距离芯片不超过1cm。我的实测数据显示,添加去耦电容可使电源噪声降低60%以上。对于长线传输场景(>20cm),需要在I²C总线上拉电阻(通常4.7kΩ),但STC某些型号(如STC8系列)已内置可编程上拉,可通过代码启用:
c复制P_SW2 |= 0x80; // 使能I²C内部上拉(STC8系列)
特别注意ADS1115的地址引脚ADDR连接方式:悬空时为0x48,接GND为0x49,接VCC为0x4A。在多设备系统中,我曾因地址冲突导致通信失败,后来采用下图配置解决了问题:
code复制[VCC]---[ADS1115#1 ADDR:GND]---[ADS1115#2 ADDR:VCC]
(地址0x49) (地址0x4A)
2.2 抗干扰设计经验
在电机控制项目中,ADC读数常受PWM干扰。通过以下措施可显著改善:
- 在ADS1115输入引脚加RC滤波(如10kΩ+0.1μF)
- I²C走线远离高频信号线
- 采用屏蔽双绞线连接传感器
- 在代码中增加数字滤波(后文详述)
我的实测案例显示,采取这些措施后,在变频器工作时ADC读数波动从±50LSB降至±3LSB。
3. STC单片机程序开发详解
3.1 I²C底层驱动实现
STC单片机通常没有硬件I²C,需用GPIO模拟。以下是经多个项目验证的稳定驱动代码:
c复制#define ADS1115_ADDR 0x48 // ADDR接地时的地址
void I2C_Delay() {
_nop_(); _nop_(); _nop_(); _nop_();
}
void I2C_Start() {
SDA = 1; I2C_Delay();
SCL = 1; I2C_Delay();
SDA = 0; I2C_Delay();
SCL = 0; I2C_Delay();
}
void I2C_WriteByte(u8 dat) {
u8 i;
for(i=0; i<8; i++) {
SDA = (dat & 0x80) ? 1 : 0;
dat <<= 1;
I2C_Delay();
SCL = 1; I2C_Delay();
SCL = 0; I2C_Delay();
}
SDA = 1; I2C_Delay(); // 释放SDA线
SCL = 1; I2C_Delay(); // 等待ACK
if(SDA) { /* 处理NACK */ }
SCL = 0; I2C_Delay();
}
关键点:STC的GPIO切换速度较快,必须插入适当延时。我曾因延时不足导致通信失败,后来用逻辑分析仪捕获波形发现SCL周期需>2.5μs。
3.2 ADS1115寄存器配置
ADS1115有4个关键寄存器:
- 转换寄存器(只读):存放转换结果
- 配置寄存器:
- OS[15]:启动转换
- MUX[14:12]:输入选择
- PGA[11:9]:增益设置
- MODE[8]:连续/单次模式
- DR[7:5]:数据速率
- COMP_*:比较器设置
以下是配置单次转换模式的典型代码:
c复制void ADS1115_Config(u8 ch, u16 gain) {
u16 config = 0x8000; // OS=1启动单次转换
config |= (ch << 12); // 设置通道
config |= (gain << 9); // 设置PGA增益
config |= 0x0100; // 单次转换模式
config |= 0x0080; // 128SPS
I2C_Start();
I2C_WriteByte(ADS1115_ADDR<<1);
I2C_WriteByte(0x01); // 指向配置寄存器
I2C_WriteByte(config >> 8);
I2C_WriteByte(config & 0xFF);
I2C_Stop();
}
实际应用中发现:配置后需延时(1ms + 1/DR)才能读取结果。例如设置128SPS(7.8ms/次)时,最少需延时8ms。
4. 数据采集与处理技巧
4.1 高精度读数实现
ADS1115返回16位有符号数,需转换为实际电压:
c复制float ADS1115_ReadVoltage() {
int16_t raw;
I2C_Start();
I2C_WriteByte(ADS1115_ADDR<<1);
I2C_WriteByte(0x00); // 指向转换寄存器
I2C_Start();
I2C_WriteByte((ADS1115_ADDR<<1)|1);
raw = (I2C_ReadByte() << 8) | I2C_ReadByte();
I2C_Stop();
float voltage;
switch(gain_setting) {
case 0: voltage = raw * 6.144 / 32768; break; // ±6.144V
case 1: voltage = raw * 4.096 / 32768; break; // ±4.096V
// 其他增益...
}
return voltage;
}
在电池监测项目中,我发现两个重要细节:
- 负电压读数以补码形式表示,需用int16_t类型处理
- 实际精度受噪声影响,连续采样16次取平均可提升2-3位有效分辨率
4.2 数字滤波算法优化
针对工业现场干扰,我总结出三级滤波方案:
- 硬件级:前述RC滤波
- 软件实时滤波:
c复制#define FILTER_LEN 8 int32_t filter_buf[FILTER_LEN]; int16_t MovingAvgFilter(int16_t new_val) { static u8 index = 0; static int32_t sum = 0; sum -= filter_buf[index]; filter_buf[index] = new_val; sum += new_val; index = (index + 1) % FILTER_LEN; return sum / FILTER_LEN; } - 后处理滤波:采集100ms数据后用中值+均值复合滤波
实测表明,这种组合滤波可使波动幅度降低90%以上,且响应延迟控制在50ms内。
5. 典型应用案例与故障排查
5.1 热电偶温度测量实例
采用K型热电偶(灵敏度约41μV/℃)时,配置要点:
- PGA增益设为8(±0.512V)
- 冷端补偿用DS18B20
- 线性化处理采用查表法
关键代码片段:
c复制float Read_Thermocouple() {
ADS1115_Config(0, 0x01); // AIN0, PGA=8
DelayMs(10);
float mv = ADS1115_ReadVoltage() * 1000;
float temp = mv / 0.041; // 简易线性化
temp += DS18B20_Read(); // 冷端补偿
return temp;
}
5.2 常见问题速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 读数始终为0 | I²C地址错误 | 检查ADDR引脚电压 |
| 数据跳变严重 | 电源噪声大 | 增加去耦电容,缩短走线 |
| 偶尔通信失败 | 总线竞争 | 增加重试机制,降低SCL频率 |
| 负电压读数错误 | 未使用有符号数据类型 | 将raw数据声明为int16_t |
| 转换值饱和(32767) | 输入超量程 | 调整PGA增益或分压电路 |
在某个工业项目中,我们遇到读数周期性跳变的问题,最终发现是变频器导致的共模干扰。解决方案是:
- 改用差分输入模式
- 在信号线加共模扼流圈
- 软件上采用滑动窗口滤波
6. 低功耗设计技巧
对于电池供电设备,ADS1115的自动关机模式可大幅降低功耗:
c复制void Enter_LowPowerMode() {
// 配置为单次转换+最低速率
u16 config = 0x8000 | (0x000); // 单次+8SPS
I2C_WriteReg(0x01, config);
// STC进入空闲模式
PCON |= 0x01; // IDL=1
_nop_();
}
实测数据对比:
- 连续模式:0.9mA @128SPS
- 单次模式(1次/秒):平均15μA
配合STC单片机的掉电模式,可使系统整体功耗降至50μA以下,纽扣电池可工作1年以上。
