【ESP32-S3】电压检测模块的使用背景理论计算方式前置知识什么是ADC分辨率引脚的选取ESP32-S3和ARDUINO的ADC分辨率是多少ESP32-S3如何设置分辨率电压检测模块为什么要分压从引脚读取电压的计算电压修正方法修正真实分压比修正参考电压多次采样ADC衰减修正业界通用计算方式不使用理论计算原因通用做法具体代码背景小车做好了电池也买了想要读取当前电池的电量于是了解了一下关键信息做下记录理论计算方式前置知识什么是ADC分辨率ADC分辨率决定了模拟信号转换为数字值的精细程度,也就是我们从引脚读取的原始的10进制数据含有多少个二进制数据。常见分辨率如下8位分辨率0-255256个值2的8次方10位分辨率0-10231024个值2的10次方12位分辨率0-40954096个值2的12次方16位分辨率0-6553565536个值2的16次方引脚的选取一定要选取支持adc的引脚否则读取到数值会为0。esp32s3一般情况下分布如ADC通道 可用GPIO ADC1 GPIO1 ~ GPIO10ADC2 GPIO11 ~ GPIO20ESP32-S3和ARDUINO的ADC分辨率是多少Arduino框架下ESP32默认是12位0-4095arduinio分辨率是10位0-1023ESP32-S3如何设置分辨率设置12位分辨率analogReadResolution(12)电压检测模块为什么要分压ESP32的ADC只能承受3.3V分压后高电压不会损坏芯片可以测量比3.3V更高的电压最大25V隔离高压部分降低风险模块化设计方便使用从引脚读取电压的计算计算过程如下图您的电压检测系统 电池电压 (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_actual5.00VadcValue819ADC_RESOLUTION4095V_ref3.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.1VADC 会 “饱和”读数固定在最大值无法准确测量。ADC 衰减就是通过芯片内部的分压电路把输入的高电压 “衰减” 到 ADC 能准确测量的范围从而扩大测量量程。代价是衰减越大测量精度会略有下降但降幅很小对新手场景几乎可忽略。当前模块分压比是之前提到的7.58若还没实测先按此举例采样电压 实际电压 8.4V / 7.58 ≈ 1.11V参照下表衰减模式符号常量有效测量范围ADC输入电压精度特点核心适用场景0dB无衰减ADC_0db0 ~ 1.1V精度最高量程最小低电压高精度测量如0~5V电池分压后1.1V2.5dBADC_2_5db0 ~ 1.5V精度较高量程略大中低电压如0~8.4V电池分压后1.5V6dBADC_6db0 ~ 2.2V精度中等量程适中中等电压如0~15V电池分压后2.2V11dBADC_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斜率。即解一个二元一次方程ykxby是实测电压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; }
【ESP32-S3】电压检测模块的使用
发布时间:2026/6/12 23:34:35
【ESP32-S3】电压检测模块的使用背景理论计算方式前置知识什么是ADC分辨率引脚的选取ESP32-S3和ARDUINO的ADC分辨率是多少ESP32-S3如何设置分辨率电压检测模块为什么要分压从引脚读取电压的计算电压修正方法修正真实分压比修正参考电压多次采样ADC衰减修正业界通用计算方式不使用理论计算原因通用做法具体代码背景小车做好了电池也买了想要读取当前电池的电量于是了解了一下关键信息做下记录理论计算方式前置知识什么是ADC分辨率ADC分辨率决定了模拟信号转换为数字值的精细程度,也就是我们从引脚读取的原始的10进制数据含有多少个二进制数据。常见分辨率如下8位分辨率0-255256个值2的8次方10位分辨率0-10231024个值2的10次方12位分辨率0-40954096个值2的12次方16位分辨率0-6553565536个值2的16次方引脚的选取一定要选取支持adc的引脚否则读取到数值会为0。esp32s3一般情况下分布如ADC通道 可用GPIO ADC1 GPIO1 ~ GPIO10ADC2 GPIO11 ~ GPIO20ESP32-S3和ARDUINO的ADC分辨率是多少Arduino框架下ESP32默认是12位0-4095arduinio分辨率是10位0-1023ESP32-S3如何设置分辨率设置12位分辨率analogReadResolution(12)电压检测模块为什么要分压ESP32的ADC只能承受3.3V分压后高电压不会损坏芯片可以测量比3.3V更高的电压最大25V隔离高压部分降低风险模块化设计方便使用从引脚读取电压的计算计算过程如下图您的电压检测系统 电池电压 (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_actual5.00VadcValue819ADC_RESOLUTION4095V_ref3.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.1VADC 会 “饱和”读数固定在最大值无法准确测量。ADC 衰减就是通过芯片内部的分压电路把输入的高电压 “衰减” 到 ADC 能准确测量的范围从而扩大测量量程。代价是衰减越大测量精度会略有下降但降幅很小对新手场景几乎可忽略。当前模块分压比是之前提到的7.58若还没实测先按此举例采样电压 实际电压 8.4V / 7.58 ≈ 1.11V参照下表衰减模式符号常量有效测量范围ADC输入电压精度特点核心适用场景0dB无衰减ADC_0db0 ~ 1.1V精度最高量程最小低电压高精度测量如0~5V电池分压后1.1V2.5dBADC_2_5db0 ~ 1.5V精度较高量程略大中低电压如0~8.4V电池分压后1.5V6dBADC_6db0 ~ 2.2V精度中等量程适中中等电压如0~15V电池分压后2.2V11dBADC_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斜率。即解一个二元一次方程ykxby是实测电压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; }