MicroPython 开发ESP32应用教程 之 ADC及应用实例:电池电量检测并显示
MicroPython 中的 ADC(模数转换器)模块为嵌入式开发提供了便捷的模拟信号采集功能,其核心实现基于 machine.ADC
类。以下是关键要点:
一、 ADC 基本原理
ADC 的作用是将连续变化的模拟信号(如电压、光照强度)转换为离散的数字信号,以便微控制器处理。其核心参数包含 分辨率(如 10 位或 12 位)和 输入电压范围。
1、. 硬件差异与配置
- ESP32 系列:如 ESP32-S3 支持 0-3.3V 输入,12 位分辨率(返回值 0-4095)。需注意 ADC2 通道与 Wi-Fi 功能冲突,MicroPython 固件通常仅支持 ADC1。
- 输入衰减设置:可通过
atten()
方法调整 ADC 输入电压范围,例如 ESP32 支持 0dB(0-1.1V)、6dB(0-1.5V)等衰减等级,以适配不同传感器信号。
2. 核心 API 使用方法
- 构造对象:
adc = machine.ADC(Pin(17))
。 - 读取原始值:
adc.read()
返回原始 ADC 数值adc_value
。 - 电压转换公式:
例如 ESP32-S3 计算电压:电压值 = (ADC原始值adc_value / 最大分辨率) * 参考电压
voltage = (adc_value / 4095) * 3.3
。
3. 应用示例
- 电位器电压采集:通过 ADC 读取引脚电压并显示在 OLED 屏幕,循环采样间隔可根据实际需要设置。
- 光敏传感器:结合 ADC 读取光照强度,动态调整 LED 亮度(需配合 PWM 模块)。
4. 注意事项
- 噪声抑制:ADC 易受电源干扰,建议硬件设计时增加滤波电路。
- 精度限制:ESP 系列 ADC 线性度较差,高精度场景需外部 ADC 芯片。
通过合理配置衰减、采样精度及数据处理逻辑,MicroPython ADC 可广泛应用于传感器数据采集、环境监测等物联网场景。
二、Micropython ADC的配置与使用
在 ESP32 上使用 MicroPython 的 ADC 模块时,需注意其特有的硬件配置和限制。以下是详细的配置步骤和代码示例(以锂电池的电量检测为例):
1. 硬件准备
- ESP32s3 开发板( ESP32-s3-WROOM-1)。
- ADC 输入源(锂电池电量检测)。电路如下所示:
- 接线:将需要检测的电压信号点连接到 ESP32 的 ADC 引脚(GPIO17)。需要注意的是,在检测之前需要将GPIO18置高,否则无法检测有效的锂电池电量。
2. 初始化 ADC
ESP32 的 ADC 通道分为 ADC1 和 ADC2,但 ADC2 与 Wi-Fi 功能冲突,因此在 Wi-Fi 启用时只能使用 ADC1。
from machine import ADC,Pinadc = ADC(Pin(17))
3. 配置输入电压范围(衰减设置)
ESP32 ADC 默认支持 0-1.1V(11dB 衰减),但可以通过 atten()
方法调整输入范围:
衰减值 | 电压范围 | 适用场景 |
---|---|---|
ADC.ATTN_0DB | 0-1.1V | 低电压传感器(如光敏) |
ADC.ATTN_2_5DB | 0-1.5V | 中等电压 |
ADC.ATTN_6DB | 0-2.2V | 常用范围 |
ADC.ATTN_11DB | 0-3.3V | 高电压(如电位器) |
设置衰减
adc.atten(ADC.ATTN_11DB) # 允许输入 0-3.3V 电压
4. 设置分辨率
ESP32 ADC 支持 9-12 位分辨率,通过 width()
方法调整:
adc.width(ADC.WIDTH_12BIT) # 12 位分辨率(0-4095)
5. 读取原始值并转换为电压
读取原始 ADC 值
def read_battery_voltage():raw = adc.read() # 读取原始值voltage = raw / 4095 * 3.3 # 转换为电压(分压后的电压)return voltage * 2 # 计算实际电池电压,之所以乘以2与我们的电路有关,请参考上面的电路
6. 注意事项
-
ADC2 与 Wi-Fi 冲突:
使用 ADC2 时需禁用 Wi-Fi,否则会抛出异常: -
噪声抑制:
- 在信号线上并联 0.1μF 电容。
- 软件端可通过 均值滤波 提高稳定性:
-
ADC 线性度问题:
ESP32 内置 ADC 的精度较低(非线性误差约 ±5%),高精度场景建议使用 外部 ADC 芯片(如 ADS1115)。
三、锂电池电量检测方法介绍
锂电池电量检测的核心原理基于电池电化学特性与电参数关联性,主要方法可分为以下三类:
一)、电压测量法
-
原理
通过测量电池端电压估算剩余电量,依赖锂电池电压与荷电状态(SOC)的非线性关系。例如:- 满电电压 ≈ 4.2V(对应 100% SOC)
- 欠压截止 ≈ 3.2V(对应 0% SOC)
-
实现方式
- 静态检测:空载时直接读取电压,适用于低功耗场景(如待机模式)
- 动态补偿:结合负载电流对压降的实时修正,公式为:
其中V_corrected = V_measured + I_load × R_internal
R_internal
为电池内阻。但实际应用中,我们往往很难准确获取电流及电池电阻,所以补偿电压很多时候也是一个大概的经验值。在我们的实例中,甚至没有作动态补偿。
-
优缺点
- 优点:成本低、实现简单,适用于静态负载设备(如电子秤)
- 缺点:
- 电压-SOC 曲线非线性显著(如 3.7-4.2V 区间变化剧烈)
- 动态负载下电压波动导致误差(如电动车启动时电量显示骤降)
二)、充放电曲线法(OCV 法)
-
原理
基于电池开路电压(OCV)与 SOC 的对应关系建立查表数据库,通过实测电压反向映射剩余电量。 -
实现步骤
- 标定阶段:使用高精度库仑计记录不同 SOC 下的 OCV 值,生成校准曲线
- 应用阶段:设备休眠时测量 OCV,结合温度补偿算法查表输出 SOC
-
优化方案
- 分段线性化处理电压-SOC 曲线,降低查表复杂度
- 引入老化因子动态修正曲线(如循环次数对容量的影响)
三)、库仑计法(电流积分法)
-
原理
通过实时监测充/放电电流,对时间积分计算电荷量:
Q_remaining = Q_initial ± ∫I(t)dt
其中
Q_initial
为初始电量 -
硬件实现
- 检流电阻:串联在电池回路中(常用 10mΩ-100mΩ 阻值)
- ADC 采样:采集电阻两端压差计算电流
- 温度补偿:集成 NTC 传感器修正内阻温漂误差
-
校准机制
- 满充复位:充电至截止电压时自动重置容量计数器
- 开路电压校验:定期休眠测量 OCV,修正累积误差
四)、复合算法与扩展技术
-
融合模型
结合电压法、库仑计及电池模型(如等效电路模型),提升全工况精度:- 低 SOC 时依赖电压阈值
- 高 SOC 时启用电流积分
-
电化学阻抗谱(EIS)
通过施加交流扰动信号分析阻抗频谱,推算电池健康状态(SOH)与 SOC -
AI 预测
基于循环伏安(CV)数据训练神经网络,实现动态负载下的 SOC 预估
五)、典型应用场景对比
方法 | 精度误差 | 成本 | 适用场景 | 代表方案 |
---|---|---|---|---|
电压测量法 | 10-20% | 低 | 低端玩具、电动自行车 | LED 分级显示 |
充放电曲线法 | 5-10% | 中 | 手机、智能穿戴设备 | OCV 查表算法 |
库仑计法 | 1-3% | 高 | 医疗设备、电动汽车 | TI BQ 系列芯片 |
四、实例讲解
本例采用的是电压测量法,有兴趣的朋友可以自行探索后面两种锂电池电量的检测方法。
显示部分请参考:MicroPython for ESP32开发st7789 TFT显示屏驱动、ST7735TFT 显示屏驱动
1、 BatteryStatus(电池电量检测模块)
为了方便,我们将电池电量检测功能封装成了class BatteryStatus:
from micropython import const
#import time# 锂电池电压与电量对应关系(以3.7V LiPo为例)
VOLTAGE_MIN = const(3.2) # 电量0%对应电压
VOLTAGE_MAX = const(4.2) # 电量100%对应电压class BatteryStatus:CheckBATInterval = 0voltage_min = VOLTAGE_MINvoltage_max = VOLTAGE_MAXdef __init__(self, adc, adc_atten,adc_width,power=None):# 初始化ADC引脚(示例使用GPIO34)self.adc = adcself.adc.atten(adc_atten)self.adc.width(adc_width)self.power = power #根据前面的电路图,我们知道,检测电池电量前GPIO18必须置高def bat_config(self,v_min,v_max):self.voltage_min = v_minself.voltage_max = v_maxdef read_battery_voltage(self):if self.power is not None:self.power(1) #根据前面的电路图,我们知道,检测电池电量前GPIO18必须置高raw = self.adc.read() # 读取原始值if self.power is not None:self.power(0)voltage = raw / 4095 * 3.3 # 转换为电压(分压后的电压)return voltage * 2 # 计算实际电池电压,之所以乘以2与电路有关,请参考前面的电路图def voltage_to_percent(self,voltage):if voltage >= self.voltage_max:return 100elif voltage <= self.voltage_min:return 0else:percent = (voltage - self.voltage_min) / (self.voltage_max - self.voltage_min) * 100return round(percent, 1)def battery_monitor(self):
# while True:v = self.read_battery_voltage()percent = self.voltage_to_percent(v)
# print(f"Voltage: {v:.2f}V, Percent: {percent}%")return percent
# time.sleep(6) # 每分钟检测一次
结合前面的知识点及代码中的注释,相信大家很容易能明白,这部分代码就不多讲解。
2、增加显示电量的接口
在现有的显示模块ST7789中增加显示电池电量的接口:
def battery_status(self,x,y,width = 24,height = 16,percent=90,c=color(0,0xff,0)):self.rect(x,y,width,height,c)width = int((width - 4) * percent / 100)self.rect(x + 2, y + 2,width,height - 4,c,True)
3、电池电量检测模块的初始化
def battery_status_init():bat_power = Pin(18,Pin.OUT)adc = ADC(Pin(17))batstatus = BatteryStatus(adc,ADC.ATTN_11DB,ADC.WIDTH_12BIT,bat_power)batstatus.bat_config(3.2,4.18) #设置最低电压及最高电压return batstatus
4、定时检测电池电量
tim = Timer(3)tim.init(period = MOINTOR_Interval,mode=Timer.PERIODIC,callback=monitor)def monitor(t):global bat_intervalglobal chgbat_statusbat_interval += 1if bat_interval >= (BAT_Interval / MOINTOR_Interval):bat_interval = 0chgbat_status = TruePowerOn = Truetft.showstring("电池电量监测实验",40,60)while True:if chgbat_status or PowerOn:percent = batstatus.battery_monitor()tft.battery_status(H_Pixel - 20,0,20,12,percent)tft.show()PowerOn = False
这里利用定时器中断来实现定时检测电池电量。
关于定时器中断,大家可以参考:MicroPython 开发ESP32应用教程 之 Timer、GPIO中断
最后,完整代码 可以参考:micropythonforesp32s3电池电量检测并显示资源-CSDN文库