「一、概述」
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_00~0.8V
精密传感器(如光敏)
ADC_ATTEN_DB_2_50~1.1V
低电压信号
ADC_ATTEN_DB_60~1.35V
中等电压
ADC_ATTEN_DB_110~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) -
「校准源优先级」: -
eFuse存储的两点校准值(工厂校准) -
eFuse的Vref参考电压 -
用户提供的 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。
五、关键实践技巧
-
「噪声抑制」
-
输入引脚并联100nF陶瓷电容 -
软件多次采样取平均(推荐64次): uint32_t sum = 0;
for (int i=0; i<64; i++) {
sum += adc1_get_raw(channel);
}
int avg = sum >> 6; // 等效除以64 -
「分压电路设计」
锂电池检测典型电路: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 <driver/adc.h>
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 <driver/adc.h>
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 <driver/adc.h>
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);
}
「关键注意事项」
-
ADC2与Wi-Fi冲突时返回 ESP_ERR_INVALID_STATE -
校准需在每次修改衰减/位宽后重新执行 -
霍尔传感器会占用ADC1的通道0和3(GPIO36/39)
❝
本文基于ESP-IDF v4.4+编写,完整示例见ESP-IDF示例目录:
examples/peripherals/adcexamples/peripherals/adc2❞