以下是一个基于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 以内(受校准、噪声、硬件影响)。

四、优化与扩展建议

  1. 硬件滤波:在信号输入端增加 RC 滤波电路(100Ω 电阻 + 100nF 电容),可进一步降低高频噪声。
  2. 动态采样:根据信号变化速度调整采样间隔(如快速变化的信号减少间隔,缓慢变化的信号增加间隔)。
  3. 多通道测量:如需测量多个信号,可添加 ADC1 的其他通道(如 GPIO37、GPIO38 等),复用初始化函数并分别读取。
  4. Wi-Fi 共存:若需同时使用 Wi-Fi,确保仅使用 ADC1 通道(ADC2 会与 Wi-Fi 冲突)。

该示例可直接用于测量 0~3.3V 的模拟信号,适用于传感器数据采集(如光敏电阻、温湿度传感器模拟输出)、电压监测等实际场景。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐