ESP32 ADC电压测量实战代码解析
本文提供了一个基于ESP32 ADC模块的实际电压测量解决方案,包含硬件连接、代码实现和优化建议。硬件部分指导连接电位器到GPIO36(ADC1_CHANNEL_0),建议添加RC滤波电路。代码实现采用ESP-IDF框架,包含ADC初始化、校准和多采样平均处理,可将12位ADC原始值(0-4095)转换为实际电压(mV)。示例展示了1秒间隔的循环测量,支持eFuse校准以提高精度,典型误差±50m
·
以下是一个基于ESP32 ADC进行实际电压测量的完整代码示例,包含硬件连接说明、噪声处理和电压转换功能。该示例适用于测量外部模拟信号(如传感器输出、电位器电压等),并通过串口打印测量结果。
一、硬件准备与连接
- 测量目标:0~3.3V 直流电压(如通过电位器调节的电压);
- 硬件连接:
- 电位器(或其他模拟信号源)的两端分别接 ESP32 的 3.3V 和 GND;
- 电位器的中间抽头接 ESP32 的 GPIO36(对应 ADC1_CHANNEL_0,优先选择 ADC1 通道避免与 Wi-Fi 冲突);
- 可选:在信号输入端串联 100Ω 电阻 + 并联 100nF 电容(硬件滤波,减少噪声)。
二、代码实现(ESP-IDF v4.4+)
#include <stdio.h>
#include <stdlib.h>
#include "esp_adc_cal.h"
#include "driver/adc.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// 日志标签
static const char *TAG = "adc_measure";
// ADC 配置参数(根据硬件连接修改)
#define ADC_UNIT ADC_UNIT_1 // 使用 ADC1
#define ADC_CHANNEL ADC1_CHANNEL_0 // 对应 GPIO36
#define ADC_ATTEN ADC_ATTEN_DB_11 // 11dB 衰减(支持 0~3.3V 输入)
#define ADC_WIDTH ADC_WIDTH_BIT_12 // 12 位分辨率(0~4095)
#define SAMPLE_NUM 50 // 采样次数(取平均减少噪声)
#define DEFAULT_VREF 1100 // 默认参考电压(mV),无校准数据时使用
// 校准参数结构体
static esp_adc_cal_characteristics_t adc_chars;
/**
* @brief ADC 初始化函数(配置通道、衰减、分辨率并校准)
*/
static void adc_init(void) {
// 初始化 ADC 单元
adc1_config_width(ADC_WIDTH);
adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN);
// 校准 ADC(使用 eFuse 数据提高精度)
esp_adc_cal_value_t cal_type = esp_adc_cal_characterize(
ADC_UNIT,
ADC_ATTEN,
ADC_WIDTH,
DEFAULT_VREF,
&adc_chars
);
// 打印校准类型
switch (cal_type) {
case ESP_ADC_CAL_VAL_EFUSE_VREF:
ESP_LOGI(TAG, "校准方式:eFuse 参考电压");
break;
case ESP_ADC_CAL_VAL_EFUSE_TP:
ESP_LOGI(TAG, "校准方式:eFuse 两点校准");
break;
default:
ESP_LOGI(TAG, "校准方式:默认参考电压(%dmV)", DEFAULT_VREF);
}
}
/**
* @brief 读取 ADC 并转换为电压(mV)
* @return 测量的电压值(mV)
*/
static uint32_t adc_measure_voltage(void) {
uint32_t adc_sum = 0;
// 多次采样取平均(减少噪声)
for (int i = 0; i < SAMPLE_NUM; i++) {
adc_sum += adc1_get_raw(ADC_CHANNEL); // 读取原始 ADC 值
ets_delay_us(10); // 采样间隔(10us,避免采样过于密集)
}
uint32_t adc_raw = adc_sum / SAMPLE_NUM; // 平均原始值
// 转换原始值为电压(mV)
uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_raw, &adc_chars);
// 打印详细信息(原始值 + 电压)
ESP_LOGI(TAG, "原始值:%d,电压:%.2fV", adc_raw, voltage / 1000.0f);
return voltage;
}
/**
* @brief 主任务:循环测量并处理数据
*/
static void adc_measure_task(void *pvParameters) {
while (1) {
uint32_t voltage = adc_measure_voltage();
// 示例:根据电压值执行不同操作
if (voltage < 500) { // <0.5V
ESP_LOGI(TAG, "信号过弱(<0.5V)");
} else if (voltage > 3000) { // >3.0V
ESP_LOGI(TAG, "信号强(>3.0V)");
}
vTaskDelay(pdMS_TO_TICKS(1000)); // 1秒测量一次
}
}
void app_main(void) {
// 初始化 ADC
adc_init();
// 创建 ADC 测量任务
xTaskCreate(
adc_measure_task, // 任务函数
"adc_measure_task", // 任务名称
2048, // 任务栈大小
NULL, // 传入参数
5, // 任务优先级
NULL // 任务句柄
);
}
三、代码说明
1. 核心功能解析
- ADC 初始化:
adc_init()函数配置 ADC1 的通道 0(GPIO36),设置 11dB 衰减(支持 0~3.3V 输入)和 12 位分辨率,并通过esp_adc_cal_characterize()进行校准,提高测量精度。 - 电压测量:
adc_measure_voltage()函数通过多次采样(50次)取平均,减少噪声干扰,再通过校准参数将原始 ADC 值(0~4095)转换为实际电压(mV)。 - 任务调度:主函数创建独立任务循环测量,避免阻塞其他操作,适合在复杂项目中集成。
2. 关键参数说明
- 采样次数(SAMPLE_NUM):设置为 50 次,平衡测量精度和响应速度(次数越多,噪声越小,但耗时越长)。
- 衰减配置(ADC_ATTEN):11dB 衰减支持 0~3.3V 输入,若测量范围更小(如 0~1V),可改用 0dB 衰减(精度更高)。
- 校准:利用 ESP32 内置的 eFuse 校准数据(如参考电压),避免因芯片个体差异导致的测量误差。
3. 实际测量效果
- 当调节电位器时,串口会输出类似日志:
I (1234) adc_measure: 原始值:2048,电压:1.65V I (2234) adc_measure: 原始值:3072,电压:2.48V I (3234) adc_measure: 原始值:1024,电压:0.82V - 测量误差通常在 ±50mV 以内(受校准、噪声、硬件影响)。
四、优化与扩展建议
- 硬件滤波:在信号输入端增加 RC 滤波电路(100Ω 电阻 + 100nF 电容),可进一步降低高频噪声。
- 动态采样:根据信号变化速度调整采样间隔(如快速变化的信号减少间隔,缓慢变化的信号增加间隔)。
- 多通道测量:如需测量多个信号,可添加 ADC1 的其他通道(如 GPIO37、GPIO38 等),复用初始化函数并分别读取。
- Wi-Fi 共存:若需同时使用 Wi-Fi,确保仅使用 ADC1 通道(ADC2 会与 Wi-Fi 冲突)。
该示例可直接用于测量 0~3.3V 的模拟信号,适用于传感器数据采集(如光敏电阻、温湿度传感器模拟输出)、电压监测等实际场景。
更多推荐



所有评论(0)