一、概述
ESP32 集成了 2 个 12 位逐次逼近模数转换器 (SARADC),支持 18 个测量通道(模拟使能引脚)。
支持以下通道:
ADC1:
- 8通道:GPIO32 - GPIO39
ADC2:
- 10个通道:GPIO0、GPIO2、GPIO4、GPIO12-GPIO15、GOIO25-GPIO27
ESP-IDF 编程指南——ADC
1.1 ADC限制
- Wi-Fi 驱动程序使用了
ADC2
。因此,应用程序只能在未启动 Wi-Fi 驱动程序时使用ADC2
。 - 某些
ADC2
引脚用作捆扎引脚(GPIO 0,2,15),因此无法自由使用。
ESP32 DevKitC : 由于外部自动编程电路,无法使用 GPIO 0。
ESP-WROVER-KIT : GPIO 0, 2, 4 和 15 由于不同用途的外部连接而无法使用。
1.2 ADC 采样模式
每个 ADC 单元支持两种工作模式,ADC 单次采样模式和ADC连续采样(DMA)模式。
-
ADC 单次采样模式
适用于低频采样操作。 -
ADC 连续采样(DMA)模式
适用于高频连续采样动作。
二、API说明
以下 ADC 接口位于 driver/esp32/include/driver/adc.h 、 driver/include/driver/adc_common.h 和 esp_adc_cal/include/esp_adc_cal.h。
2.1 adc1_config_width
2.2 adc1_config_channel_atten
2.3 adc1_get_raw
2.4 esp_adc_cal_check_efuse
2.5 esp_adc_cal_characterize
2.6 esp_adc_cal_raw_to_voltage
三、编程流程
3.1 设置精度、衰减倍数和通道引脚
ADC 应该在读取之前配置。
- 对于 ADC1,通过调用函数
adc1_config_width()
和配置所需的精度和衰减adc1_config_channel_atten()
。- 对于 ADC2,将衰减配置为
adc2_config_channel_atten()
。每次读取时都会配置ADC2的读取宽度。
- 精度
ESP32的内置12位ADC可以在9位到12位的精度之间调整。
typedef enum {
ADC_WIDTH_BIT_9 = 0, /*!< ADC capture width is 9Bit*/
ADC_WIDTH_BIT_10 = 1, /*!< ADC capture width is 10Bit*/
ADC_WIDTH_BIT_11 = 2, /*!< ADC capture width is 11Bit*/
ADC_WIDTH_BIT_12 = 3, /*!< ADC capture width is 12Bit*/
ADC_WIDTH_MAX,
} adc_bits_width_t;
-
衰减倍数
不同的衰减倍数对应不同的检测电压范围。ADC的默认满量程电压为1.1V。要读取更高的电压(最高为引脚最大电压,通常为3.3V),则需要将该ADC通道的信号衰减设置为> 0dB。
当VDD_A为3.3V时:
- 0dB衰减(ADC_ATTEN_0db)表示参考电压为1.1V
- 2.5dB衰减(ADC_ATTEN_2_5db)表示参考电压为1.5V
- 6dB衰减(ADC_ATTEN_6db)表示参考电压为2.2V
- 11dB衰减(ADC_ATTEN_11db)表示参考电压为3.9V
typedef enum {
ADC_ATTEN_DB_0 = 0, /*!
- 通道引脚
两个12位的ADC,其中ADC1(8个通道,连接到GPIO 32-39)和ADC2(10个通道,连接到GPIO 0、2、4、12-15和25-27)。
typedef enum {
ADC1_CHANNEL_0 = 0, /*!< ADC1 channel 0 is GPIO36 */
ADC1_CHANNEL_1, /*!< ADC1 channel 1 is GPIO37 */
ADC1_CHANNEL_2, /*!< ADC1 channel 2 is GPIO38 */
ADC1_CHANNEL_3, /*!< ADC1 channel 3 is GPIO39 */
ADC1_CHANNEL_4, /*!< ADC1 channel 4 is GPIO32 */
ADC1_CHANNEL_5, /*!< ADC1 channel 5 is GPIO33 */
ADC1_CHANNEL_6, /*!< ADC1 channel 6 is GPIO34 */
ADC1_CHANNEL_7, /*!< ADC1 channel 7 is GPIO35 */
ADC1_CHANNEL_MAX,
} adc1_channel_t;
typedef enum {
ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO4 */
ADC2_CHANNEL_1, /*!< ADC2 channel 1 is GPIO0 */
ADC2_CHANNEL_2, /*!< ADC2 channel 2 is GPIO2 */
ADC2_CHANNEL_3, /*!< ADC2 channel 3 is GPIO15 */
ADC2_CHANNEL_4, /*!< ADC2 channel 4 is GPIO13 */
ADC2_CHANNEL_5, /*!< ADC2 channel 5 is GPIO12 */
ADC2_CHANNEL_6, /*!< ADC2 channel 6 is GPIO14 */
ADC2_CHANNEL_7, /*!< ADC2 channel 7 is GPIO27 */
ADC2_CHANNEL_8, /*!< ADC2 channel 8 is GPIO25 */
ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 */
ADC2_CHANNEL_MAX,
} adc2_channel_t;
3.2 读取转换结果
用adc1_get_raw()
和读取 ADC 转换结果adc2_get_raw()
。ADC2 的读取宽度应设置为参数adc2_get_raw()
而不是在配置函数中。
也可以通过调用专用函数通过 ADC1 读取内部霍尔效应传感器hall_sensor_read()
。请注意,即使霍尔传感器也是 ESP32 内部的,从它读取使用 ADC1 的通道 0 和 3(GPIO 36 和 39)。不要将任何其他东西连接到这些引脚,也不要更改它们的配置。否则可能会影响来自传感器的低值信号的测量。
此 API 提供了配置 ADC1 以从ULP读取的便捷方法。为此,请调用函数adc1_ulp_enable()
,然后如上所述设置精度和衰减。
还有另一个特定功能adc_vref_to_gpio()
用于将内部参考电压路由到 GPIO 引脚。
四、应用实例
4.1 ADC1单次采集
读取 ADC1 通道 7 (GPIO 35) 上的电压,输入电压为 0 至 1.1 V(0 dB 衰减)
具体代码查看 esp-idf\examples\peripherals\adc 中的例程
#include
static const adc_channel_t channel = ADC1_CHANNEL_7; //GPIO35 if ADC1
...
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(channel, ADC_ATTEN_DB_0);
int val = adc1_get_raw(channel);
4.2 ADC2单次采集
读取 ADC2 通道 7 (GPIO 27) 上的电压
具体代码查看 esp-idf\examples\peripherals\adc2 中的例程
#include
...
int read_raw;
adc2_config_channel_atten( ADC2_CHANNEL_7, ADC_ATTEN_0db );
esp_err_t r = adc2_get_raw( ADC2_CHANNEL_7, ADC_WIDTH_12Bit, &read_raw);
if ( r == ESP_OK ) {
printf("%d\n", read_raw );
} else if ( r == ESP_ERR_TIMEOUT ) {
printf("ADC2 used by Wi-Fi.\n");
}
读取可能会因为与 Wi-Fi 冲突而失败,如果该 API 的返回值为ESP_ERR_INVALID_STATE,则读取结果无效。
4.3 ADC DMA
具体代码查看 components/driver/test/adc_dma_test 中的例程
4.4 ADC校准
具体代码查看 esp-idf\examples\peripherals\adc 中的例程
在特定衰减下表征 ADC:
#include "driver/adc.h"
#include "esp_adc_cal.h"
...
//Characterize ADC at particular atten
esp_adc_cal_characteristics_t *adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
//Check type of calibration value used to characterize ADC
if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
printf("eFuse Vref");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
printf("Two Point");
} else {
printf("Default");
}
读取 ADC,然后将读数转换为电压:
#include "driver/adc.h"
#include "esp_adc_cal.h"
...
uint32_t reading = adc1_get_raw(ADC1_CHANNEL_5);
uint32_t voltage = esp_adc_cal_raw_to_voltage(reading, adc_chars);
将 ADC 参考电压路由到 GPIO,因此可以手动测量(对于默认 Vref):
#include "driver/adc.h"
...
esp_err_t status = adc_vref_to_gpio(ADC_UNIT_1, GPIO_NUM_25);
if (status == ESP_OK) {
printf("v_ref routed to GPIO\n");
} else {
printf("failed to route v_ref\n");
}
4.5 读取内部霍尔效应传感器
#include
...
adc1_config_width(ADC_WIDTH_BIT_12);
int val = hall_sensor_read();
• 由 Leung 写于 2021 年 6 月 4 日
• 参考:ESP32 开发笔记(三)源码示例 4_ADC_LightR 利用ADC读取光敏电阻实现光线传感
ESP32-ADC学习
ESP32S2的ADC出坑记录