ESPIDF-ADC

概述

ESP32 集成了 2 个 12-bit SAR(逐次逼近寄存器) ADC,共支持 18 个模拟通道输入。为了实现更低功耗,ESP32 的 ULP 协处理器也可以在睡眠方式下测量电压,此时,可通过设置阈值或其他触发方式唤醒 CPU。
通过适当的设置,最多可配置 18 个管脚的 ADC,用于电压模数转换。

ADC通道

  1. ADC1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**** `adc1_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
    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;
  2. ADC2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**** `adc2_channel_t` will be deprecated functions, combine into `adc_channel_t` ********/
    typedef enum {
    ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO4 (ESP32), GPIO11 (ESP32-S2) */
    ADC2_CHANNEL_1, /*!< ADC2 channel 1 is GPIO0 (ESP32), GPIO12 (ESP32-S2) */
    ADC2_CHANNEL_2, /*!< ADC2 channel 2 is GPIO2 (ESP32), GPIO13 (ESP32-S2) */
    ADC2_CHANNEL_3, /*!< ADC2 channel 3 is GPIO15 (ESP32), GPIO14 (ESP32-S2) */
    ADC2_CHANNEL_4, /*!< ADC2 channel 4 is GPIO13 (ESP32), GPIO15 (ESP32-S2) */
    ADC2_CHANNEL_5, /*!< ADC2 channel 5 is GPIO12 (ESP32), GPIO16 (ESP32-S2) */
    ADC2_CHANNEL_6, /*!< ADC2 channel 6 is GPIO14 (ESP32), GPIO17 (ESP32-S2) */
    ADC2_CHANNEL_7, /*!< ADC2 channel 7 is GPIO27 (ESP32), GPIO18 (ESP32-S2) */
    ADC2_CHANNEL_8, /*!< ADC2 channel 8 is GPIO25 (ESP32), GPIO19 (ESP32-S2) */
    ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 (ESP32), GPIO20 (ESP32-S2) */
    ADC2_CHANNEL_MAX,
    } adc2_channel_t;

注意:ADC2 模块也被 Wi-Fi 使用,当它们一起使用时,有一个会被抢占,导致 adc2_get_raw() 可能会被阻塞,直到 Wi-Fi 停止。即 ADC2 不能与 WIFI 同时使用

捕获宽度

1
2
3
4
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衰减

ADC模块 能读取电压的范围(量程)有限,因此我们一般给某个 ADC 通道配置一定的衰减,使其读取更大的电压。但是,更大的量程会导致更小的精度。因此根据 ADC 的应用场景,选择适当的衰减级别十分必要。

1
2
3
4
5
6
7
8
9
10
/**
* @brief ADC attenuation parameter. Different parameters determine the range of the ADC. See ``adc1_config_channel_atten``.
*/
typedef enum {
ADC_ATTEN_DB_0 = 0, /*!<No input attenumation, ADC can measure up to approx. 800 mV. */
ADC_ATTEN_DB_2_5 = 1, /*!<The input voltage of ADC will be attenuated extending the range of measurement by about 2.5 dB (1.33 x) */
ADC_ATTEN_DB_6 = 2, /*!<The input voltage of ADC will be attenuated extending the range of measurement by about 6 dB (2 x) */
ADC_ATTEN_DB_11 = 3, /*!<The input voltage of ADC will be attenuated extending the range of measurement by about 11 dB (3.55 x) */
ADC_ATTEN_MAX,
} adc_atten_t;

说明:

  • Atten = 3 时,测量值大于 3,000(电压值约为 2,450 mV)之后,精度会降低。
  • 使用过滤器多次采样或计算平均值可以获得更好的 DNL(差分非线性) 结果。
  • 默认情况下,芯片之间的测量差异会有 ±6%。ESP-IDF 提供了对 ADC1 的多种校准方法。

使用 ADC1

对于 ADC1 我们主要使用3个 API 函数:

  • esp_err_t adc1_config_width(adc_bits_width_t width_bit); 配置ADC1所有通道的捕获宽度。
  • esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten); 配置ADC1某个通道的衰减。
  • int adc1_get_raw(adc1_channel_t channel); 读取 1 次 ADC 值。

示例:使用 ADC1 单次读取 channel 0 (GPIO36),位宽 12 BIT,衰减 11 db

1
2
3
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_DB_11);
int val = adc1_get_raw(ADC1_CHANNEL_0);

使用 ADC2

对于 ADC2 我们主要使用3个 API 函数:

  • esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten); 配置 ADC2 的衰减.
  • esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out); 该函数有两个参数,返回值不是直接返回测量值,测量值需要用指针从参数中获取。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
int read_raw;
adc2_config_channel_atten( ADC2_CHANNEL_7, ADC_ATTEN_0db );
esp_err_t err = adc2_get_raw( ADC2_CHANNEL_7, ADC_WIDTH_12Bit, &read_raw);
// 判断读取是否成功
if (err == ESP_OK)
{
printf("读取到的值为:%d\n", read_raw );
}
else if ( r == ESP_ERR_TIMEOUT )
{
printf("ADC2 被占用\n");
}

参考链接