ESP32学习笔记(22)——ADC接口使用

一、概述

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.hdriver/include/driver/adc_common.hesp_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出坑记录

你可能感兴趣的:(ESP32学习笔记(22)——ADC接口使用)