十七、【ESP32全栈开发指南:ADC接口使用】

一、概述
ESP32集成两个12位逐次逼近型模数转换器(SARADC),共支持18个模拟输入通道:

  • ADC1:8通道(GPIO32-GPIO39)
  • ADC2:10通道(GPIO0、GPIO2、GPIO4、GPIO12-GPIO15、GPIO25-GPIO27)
1.1 ADC限制
  • ADC2与Wi-Fi冲突
    ADC2在Wi-Fi驱动启用时不可用,需在未启动Wi-Fi时使用。
  • 硬件限制
    • 绑带引脚限制(GPIO 0/2/15)
    • ESP32 DevKitC:GPIO0被编程电路占用
    • ESP-WROVER-KIT:GPIO 0/2/4/15因外设连接不可用
1.2 ADC采样模式
模式 适用场景
单次采样模式 低频采样(如传感器读取)
连续采样模式 高频采样(需DMA支持)

二、API说明
关键头文件:

  • driver/adc.h
  • driver/adc_common.h
  • esp_adc_cal.h
1. 位宽配置 - adc1_config_width()
esp_err_t adc1_config_width(adc_bits_width_t width);
  • 功能:设置ADC1的采样分辨率(9~12位)
  • 参数
    typedef enum {
        ADC_WIDTH_BIT_9  = 0,  // 9位(量程0~511)
        ADC_WIDTH_BIT_10 = 1,  // 10位(0~1023)
        ADC_WIDTH_BIT_11 = 2,  // 11位(0~2047)
        ADC_WIDTH_BIT_12 = 3   // 12位(0~4095,推荐)
    } adc_bits_width_t;
    
  • 注意:分辨率越高精度越高,但转换时间稍长;ADC2需在每次读取时单独设置位宽。

2. 衰减配置 - adc1_config_channel_atten()
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten);
  • 功能:配置指定通道的输入电压衰减倍数,扩展测量范围
  • 衰减等级与量程对照
    衰减枚举 量程(VDD=3.3V) 适用场景
    ADC_ATTEN_DB_0 0~0.8V 精密传感器(如光敏)
    ADC_ATTEN_DB_2_5 0~1.1V 低电压信号
    ADC_ATTEN_DB_6 0~1.35V 中等电压
    ADC_ATTEN_DB_11 0~2.6V 电池电压(需分压)
  • 硬件设计关键:超出0.8V必须使用衰减,否则可能损坏ADC模块。

3. 原始值读取 - adc1_get_raw()
int adc1_get_raw(adc1_channel_t channel);
  • 返回值:12位原始数据(0~4095),需配合校准转换为实际电压
  • 阻塞特性:单次采样约10μs,适用低频场景(如温度采集)。

三、ADC校准核心API

1. 校准初始化 - esp_adc_cal_characterize()
esp_adc_cal_value_t esp_adc_cal_characterize(
    adc_unit_t unit,
    adc_atten_t atten,
    adc_bits_width_t bitwidth,
    uint32_t default_vref,
    esp_adc_cal_characteristics_t *chars
);
  • 作用:生成ADC电压特征曲线,补偿芯片间Vref差异(±100mV)
  • 校准源优先级
    1. eFuse存储的两点校准值(工厂校准)
    2. eFuse的Vref参考电压
    3. 用户提供的default_vref(默认1100mV)
  • 输出校验
    if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
        printf("使用eFuse两点校准\n");
    } else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
        printf("使用eFuse Vref校准\n");
    } else {
        printf("使用默认Vref\n");  // 精度最低
    }
    

2. 原始值转电压 - esp_adc_cal_raw_to_voltage()
uint32_t esp_adc_cal_raw_to_voltage(
    uint32_t adc_reading,
    const esp_adc_cal_characteristics_t *chars
);
  • 输入adc1_get_raw()的原始值 + 校准结构体
  • 输出:实际电压值(单位mV)
  • 示例
    uint32_t voltage = esp_adc_cal_raw_to_voltage(raw_val, &adc_chars);
    printf("电压值: %dmV\n", voltage);  // 输出如 "电压值: 1234mV"
    

四、专用功能API

1. ADC2冲突处理 - adc2_get_raw()
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width, int *raw_out);
  • Wi-Fi冲突:返回ESP_ERR_INVALID_STATE表示被Wi-Fi占用
  • 正确用法
    int raw_val;
    esp_err_t ret = adc2_get_raw(ADC2_CHANNEL_7, ADC_WIDTH_BIT_12, &raw_val);
    if (ret == ESP_ERR_INVALID_STATE) {
        // 需延迟重试或关闭Wi-Fi
    }
    

2. 内部霍尔传感器 - hall_sensor_read()
int hall_sensor_read(void);
  • 硬件要求:自动占用GPIO36(SVP)和GPIO39(SVN),不可复用
  • 示例
    adc1_config_width(ADC_WIDTH_BIT_12);  // 需先配置位宽
    int hall_val = hall_sensor_read();    // 返回值受外部磁场影响
    

3. 参考电压输出 - adc_vref_to_gpio()
esp_err_t adc_vref_to_gpio(adc_unit_t unit, gpio_num_t gpio);
  • 功能:将内部Vref输出至GPIO(如GPIO25),方便万用表实测校准
  • 使用场景:当eFuse无校准值且需要高精度时,手动测量真实Vref。

五、关键实践技巧

  1. 噪声抑制

    • 输入引脚并联100nF陶瓷电容
    • 软件多次采样取平均(推荐64次):
      uint32_t sum = 0;
      for (int i=0; i<64; i++) {
          sum += adc1_get_raw(channel);
      }
      int avg = sum >> 6;  // 等效除以64
      
  2. 分压电路设计
    锂电池检测典型电路:

    VBAT+ ─ 20kΩ ──┬── 10kΩ ── GND
                    │
                    └─ 100nF ── GND
                    │
                    └─ GPIO35 (ADC1_CH7)
    
    • 分压比 = R2/(R1+R2) = 1/3,适配3.7V电池
    • 电容滤除高频干扰

六、编程流程

3.1 配置参数

1. 位宽配置

typedef enum {  
    ADC_WIDTH_BIT_9  = 0,  // 9位精度  
    ADC_WIDTH_BIT_10 = 1,  // 10位精度  
    ADC_WIDTH_BIT_11 = 2,  // 11位精度  
    ADC_WIDTH_BIT_12 = 3   // 12位精度(默认)  
} adc_bits_width_t;  

2. 衰减系数与量程

衰减值 量程范围 (VDD=3.3V)
ADC_ATTEN_DB_0 0 ~ 0.8V
ADC_ATTEN_DB_2_5 0 ~ 1.1V
ADC_ATTEN_DB_6 0 ~ 1.35V
ADC_ATTEN_DB_11 0 ~ 2.6V

3. 通道映射

// ADC1通道与GPIO对应  
ADC1_CHANNEL_0 → GPIO36  
ADC1_CHANNEL_4 → GPIO32  // 注意索引顺序  

// ADC2通道示例  
ADC2_CHANNEL_0 → GPIO4  
ADC2_CHANNEL_9 → GPIO26  

七、应用实例

4.1 ADC1单次采样(GPIO35)
#include   

void read_adc1() {  
    adc1_config_width(ADC_WIDTH_BIT_12);  
    adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_0);  
    int val = adc1_get_raw(ADC1_CHANNEL_7);  // 读取GPIO35  
    printf("ADC1 Value: %d\n", val);  
}  
4.2 ADC2单次采样(GPIO27)
#include   

void read_adc2() {  
    int raw_val;  
    adc2_config_channel_atten(ADC2_CHANNEL_7, ADC_ATTEN_DB_11);  
    esp_err_t ret = adc2_get_raw(ADC2_CHANNEL_7, ADC_WIDTH_BIT_12, &raw_val);  

    if (ret == ESP_OK) {  
        printf("ADC2 Value: %d\n", raw_val);  
    } else if (ret == ESP_ERR_INVALID_STATE) {  
        printf("Error: Wi-Fi占用ADC2!\n");  // 处理冲突  
    }  
}  
4.3 ADC校准与电压转换
#include "esp_adc_cal.h"  

void adc_calibration() {  
    esp_adc_cal_characteristics_t adc_chars;  
    esp_adc_cal_value_t cal_type = esp_adc_cal_characterize(  
        ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars  
    );  

    int raw = adc1_get_raw(ADC1_CHANNEL_5);  
    uint32_t voltage = esp_adc_cal_raw_to_voltage(raw, &adc_chars);  
    printf("Voltage: %dmV\n", voltage);  
}  
4.4 读取内部霍尔传感器
#include   

void read_hall_sensor() {  
    adc1_config_width(ADC_WIDTH_BIT_12);  
    int hall_val = hall_sensor_read();  // 自动使用GPIO36/39  
    printf("Hall Effect: %d\n", hall_val);  
}  

关键注意事项

  1. ADC2与Wi-Fi冲突时返回ESP_ERR_INVALID_STATE
  2. 校准需在每次修改衰减/位宽后重新执行
  3. 霍尔传感器会占用ADC1的通道0和3(GPIO36/39)

本文基于ESP-IDF v4.4+编写,完整示例见ESP-IDF示例目录:

  • examples/peripherals/adc
  • examples/peripherals/adc2

你可能感兴趣的:(ESP32,esp32,adc,物联网,嵌入式,stm32,霍尔传感器)