【ESP32-S3】电压检测模块的使用
2026/6/14 16:15:32 网站建设 项目流程

【ESP32-S3】电压检测模块的使用

  • 背景
  • 理论计算方式
    • 前置知识
      • 什么是ADC分辨率
      • 引脚的选取
      • ESP32-S3和ARDUINO的ADC分辨率是多少
      • ESP32-S3如何设置分辨率
      • 电压检测模块为什么要分压
    • 从引脚读取电压的计算
    • 电压修正方法
      • 修正真实分压比
      • 修正参考电压
      • 多次采样
      • ADC衰减修正
  • 业界通用计算方式
    • 不使用理论计算原因
    • 通用做法
    • 具体代码

背景

小车做好了,电池也买了,想要读取当前电池的电量,于是了解了一下,关键信息做下记录

理论计算方式

前置知识

什么是ADC分辨率

ADC分辨率决定了模拟信号转换为数字值的精细程度,也就是我们从引脚读取的原始的10进制数据含有多少个二进制数据。常见分辨率如下

8位分辨率:0-255(256个值,2的8次方)
10位分辨率:0-1023(1024个值,2的10次方)
12位分辨率:0-4095(4096个值,2的12次方)
16位分辨率:0-65535(65536个值,2的16次方)

引脚的选取

一定要选取支持adc的引脚,否则读取到数值会为0。esp32s3一般情况下分布如
ADC通道 可用GPIO :

ADC1 GPIO1 ~ GPIO10
ADC2 GPIO11 ~ GPIO20

ESP32-S3和ARDUINO的ADC分辨率是多少

Arduino框架下,ESP32默认是12位(0-4095),arduinio分辨率是10位(0-1023)

ESP32-S3如何设置分辨率

设置12位分辨率:analogReadResolution(12)

电压检测模块为什么要分压

  1. ESP32的ADC只能承受3.3V,分压后高电压不会损坏芯片
  2. 可以测量比3.3V更高的电压(最大25V)
  3. 隔离高压部分,降低风险
  4. 模块化设计,方便使用

从引脚读取电压的计算

计算过程如下图

您的电压检测系统: 电池电压 (8.42V) │ ▼ [分压模块 5:1] 分压后电压 (1.684V) → ESP32 ADC引脚 │ ▼ [ADC转换] 数字值 (约2090) │ ▼ [软件计算] 恢复的分压电压 = (2090 ÷ 4095) × 3.3 = 1.684V,这里更好理解是这个2090x(3.3/4095) │ ▼ [乘以分压比] 电池电压 = 1.684V × 5 = 8.42V ✅

ADC_REF_VOLTAGE 这个值很重要,这里只得是板载电压是3.3v,而不是5v。是因为

模拟电压 (0-3.3V) → ADC转换 → 数字值 (0-4095)
数字值 x 3.3 /4098= 模拟电压

具体代码如下

// 完整的电压监测程序 const int VOLTAGE_PIN = 4; const float ADC_REF_VOLTAGE = 3.3; // ESP32-S3参考电压 const float DIVIDER_RATIO = 5.0; // 分压比,看电压检测模块的分压是多少 const int ADC_RESOLUTION = 4095; // 12位ADC最大值,ESP32-S3的ad引脚是12位分辨率 void setup() { Serial.begin(115200); analogReadResolution(12); analogSetAttenuation(ADC_11db); } float readBatteryVoltage() { // 1. 读取ADC值 int adcValue = analogRead(VOLTAGE_PIN); // 2. 计算分压后的电压(乘以3.3是关键!) float dividedVoltage = (adcValue / (float)ADC_RESOLUTION) * ADC_REF_VOLTAGE; // 3. 恢复实际电压 float batteryVoltage = dividedVoltage * DIVIDER_RATIO; return batteryVoltage; } void loop() { float voltage = readBatteryVoltage(); Serial.print("电池电压: "); Serial.print(voltage, 2); Serial.println("V"); // 分步显示计算过程 int adcValue = analogRead(VOLTAGE_PIN); float dividedVoltage = (adcValue / 4095.0) * 3.3; Serial.print("ADC值: "); Serial.print(adcValue); Serial.print(" → 分压后: "); Serial.print(dividedVoltage, 3); Serial.print("V → 乘以"); Serial.print(DIVIDER_RATIO); Serial.print(" → "); Serial.print(voltage, 2); Serial.println("V"); delay(1000); }

电压修正方法

修正真实分压比

先获取如下值:

实际输入电压:V_actual(万用表实测值,如 5.00V); ADC 采样值:adcValue(串口打印的原始值,如 819); ESP32 参考电压:V_ref(如 3.3V,后续会校准)。

进行如下计算

已知:V_actual=5.00V,adcValue=819,ADC_RESOLUTION=4095,V_ref=3.3V 计算:(819/4095)*3.3 = 0.66V(模块输出到 ESP32 的采样电压) 真实分压比:5.00 / 0.66 ≈ 7.58(而非理论值 5.0)

代码修正:将DIVIDER_RATIO替换为实测计算出的真实值(如 7.58)

修正参考电压

找到 ESP32-S3 的3.3V引脚(VCC_3V3)和GND引脚; 用万用表直流电压档测量这两个引脚的电压,得到V_ref_actual(如 3.28V)。

代码修正:将ADC_REF_VOLTAGE替换为实测值(如 3.28)

多次采样

float readBatteryVoltage() { const int SAMPLE_COUNT = 50; // 采样次数(次数越多越稳定,建议20~100) long adcSum = 0; // 用long避免溢出 // 多次采样累加 for (int i = 0; i < SAMPLE_COUNT; i++) { adcSum += analogRead(VOLTAGE_PIN); delayMicroseconds(100); // 短延时,避免采样过于密集 } // 计算平均ADC值 int adcValue = adcSum / SAMPLE_COUNT; // 原有计算逻辑 float dividedVoltage = (adcValue / (float)ADC_RESOLUTION) * ADC_REF_VOLTAGE; float batteryVoltage = dividedVoltage * DIVIDER_RATIO; return batteryVoltage; }

ADC衰减修正

ESP32-S3 的 ADC 默认参考电压是 3.3V,无衰减(0dB)时,只能准确测量 0~1.1V 的输入电压(这是芯片设计的安全精度范围)。如果输入电压超过 1.1V,ADC 会 “饱和”,读数固定在最大值,无法准确测量。
ADC 衰减就是通过芯片内部的分压电路,把输入的高电压 “衰减” 到 ADC 能准确测量的范围,从而扩大测量量程。代价是:衰减越大,测量精度会略有下降(但降幅很小,对新手场景几乎可忽略)。

当前模块分压比是之前提到的7.58(若还没实测,先按此举例):
采样电压 =(实际电压) 8.4V / 7.58 ≈ 1.11V

参照下表

衰减模式符号常量有效测量范围(ADC输入电压)精度特点核心适用场景
0dB(无衰减)ADC_0db0 ~ 1.1V精度最高,量程最小低电压高精度测量(如0~5V电池,分压后<1.1V)
2.5dBADC_2_5db0 ~ 1.5V精度较高,量程略大中低电压(如0~8.4V电池,分压后<1.5V)
6dBADC_6db0 ~ 2.2V精度中等,量程适中中等电压(如0~15V电池,分压后<2.2V)
11dBADC_11db0 ~ 3.9V精度略降,量程最大高电压(如0~25V电池,分压后<3.9V)

所以在esp32的代码中设置

void setup() { Serial.begin(115200); analogReadResolution(12); // 关键修改:适配8.4V电池场景,选择ADC_2_5db analogSetAttenuation(ADC_2_5db); }

业界通用计算方式

不使用理论计算原因

代码中的 DIVIDER_RATIO 是一个固定的常量(5.243)。这假设了电阻是绝对精准的,且电路是理想的。

  • 电阻精度问题: 普通电阻(如5%精度)的实际阻值可能与标称值有偏差。可能是在8.28V时反推算出了5.243这个数值,但这掩盖了电阻本身的误差。
  • 非线性负载: 如果分压电路后级接了其他负载(虽然通常ADC输入阻抗很高,影响极小),或者使用了劣质的电压检测模块(常见于淘宝购入的LM2596等模块),模块上的反馈电路可能会引入微小的非线性误差。
  • ADC输入漏电流: ESP32的ADC引脚虽然阻抗高,但在某些情况下会有微小的漏电流,这在高阻值分压电路中会引起误差。

通用做法

采用两点校准法,即分别在低电压和满电压时测量,计算出更精准的转换公式。将简单的乘法改为“截距式”计算。需要重新定义两个参数:VOLTAGE_OFFSET(截距)和 VOLTAGE_SCALE(斜率)。即解一个二元一次方程

y=kx+b

y是实测电压,k是次采样后的adc引脚读书。需要在电满和放电时两次实测。

具体代码

// 修改配置区 const float VOLTAGE_OFFSET = 0.0; // 截距,初始为0 const float VOLTAGE_SCALE = 2.55; // 斜率,需要重新计算 float readBatteryVoltage() { // ... (采样逻辑不变) ... // 新逻辑:y = kx + b float batteryVoltage = (adcValue * VOLTAGE_SCALE) + VOLTAGE_OFFSET; return batteryVoltage; }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询