Skip to content

ESP32-C3 ADC

简介

ADC(模数转换器)是将模拟信号转换为数字信号的电子元件。ESP32-C3 内置了多个 ADC 通道,可以用于测量各种模拟信号,如电压、电流、温度等。

ADC 通道

ESP32-C3 有 6 个 ADC 通道,分别为 ADC1 和 ADC2。ADC1 有 5 个通道,ADC2 有 1 个通道。每个通道都可以测量不同的模拟信号。

信号名称通道编号ADC 选择
GPIO00SAR ADC1
GPIO11SAR ADC1
GPIO22SAR ADC1
GPIO33SAR ADC1
GPIO44SAR ADC1
GPIO50SAR ADC2

注意
通道与引脚的对应关系是固定的,不能更改。

ADC 编程

在 ESP32-C3 芯片中,ADC采样可能于制造工艺的原因,其ADC采样的结果会有偏差,这个偏差值在芯片制造时进行了校准。校准后的参数保存在了efuse中了。我们在实际使用时,需要参考这些参数,再对所采样的值进行校准后计算出实际的电压值。

在实际的编程中,我们会使用一个 ESP-IDF 中的组件 esp_adc 来进行 ADC 采样。这个组件提供了一些 API 函数,可以方便地进行 ADC 采样。

1.引入组件库

所以我们在实际的开如,需要引入这个库组件。方法时在 CMakeLists.txt 中添加以下内容:

cmake
idf_component_register(SRCS "adc.c"
                       PRIV_REQUIRES esp_adc
                       INCLUDE_DIRS "")

PRIV_REQUIRES esp_adc 表示我们使用的是 esp_adc 这个库组件。

2.引入头文件

c
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"

下面代码中:

ADC_UNIT_1 是 ADC1。
EXAMPLE_ADC_ATTEN 是 ADC 的衰减系数。
ADC_BITWIDTH_DEFAULT 是 ADC 的采样位数。
EXAMPLE_ADC1_CHAN0 是 ADC1 的通道 0。
EXAMPLE_ADC1_CHAN1 是 ADC1 的通道 1。
ADC_BITWIDTH_DEFAULT 是 ADC 的采样位数。取0值,表示使用默认值。

c
#define EXAMPLE_ADC1_CHAN0          ADC_CHANNEL_0
#define EXAMPLE_ADC1_CHAN1          ADC_CHANNEL_1
#define EXAMPLE_ADC_ATTEN           ADC_ATTEN_DB_12

3.初始化 ADC

c
    //-------------ADC1 Init---------------//
    adc_oneshot_unit_handle_t adc1_handle;
    adc_oneshot_unit_init_cfg_t init_config1 = {
        .unit_id = ADC_UNIT_1,
    };
    ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config1, &adc1_handle));

4.配置 ADC

c
    //-------------ADC1 Config---------------//
    adc_oneshot_chan_cfg_t config = {
        .atten = EXAMPLE_ADC_ATTEN,
        .bitwidth = ADC_BITWIDTH_DEFAULT,
    };
    ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN0, &config));
    ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN1, &config));

这里主要是指定 ADC 的衰减系数和采样位数。衰减系统可能的取值为:

c
typedef enum {
    ADC_ATTEN_DB_0   = 0,  ///<No input attenuation, ADC can measure up to approx.
    ADC_ATTEN_DB_2_5 = 1,  ///<The input voltage of ADC will be attenuated extending the range of measurement by about 2.5 dB
    ADC_ATTEN_DB_6   = 2,  ///<The input voltage of ADC will be attenuated extending the range of measurement by about 6 dB
    ADC_ATTEN_DB_12  = 3,  ///<The input voltage of ADC will be attenuated extending the range of measurement by about 12 dB
    ADC_ATTEN_DB_11 __attribute__((deprecated)) = ADC_ATTEN_DB_12,  ///<This is deprecated, it behaves the same as `ADC_ATTEN_DB_12`
} adc_atten_t;

采样位数可能的取值为:

c
typedef enum {
    ADC_BITWIDTH_DEFAULT = 0, ///< Default ADC output bits, max supported width will be selected
    ADC_BITWIDTH_9  = 9,      ///< ADC output width is 9Bit
    ADC_BITWIDTH_10 = 10,     ///< ADC output width is 10Bit
    ADC_BITWIDTH_11 = 11,     ///< ADC output width is 11Bit
    ADC_BITWIDTH_12 = 12,     ///< ADC output width is 12Bit 最大值 4095
    ADC_BITWIDTH_13 = 13,     ///< ADC output width is 13Bit
} adc_bitwidth_t;

一般使用第1项,也就是取0,这样会自动选择最大的采样位数。

5.校准的初始化

这一步就是通过读取芯片的efuse中的参数,来生成一个用于校准的句柄。

c
    //-------------ADC1 Calibration Init---------------//
    adc_cali_handle_t adc1_cali_chan0_handle = NULL;
    adc_cali_handle_t adc1_cali_chan1_handle = NULL;
    bool do_calibration1_chan0 = example_adc_calibration_init(ADC_UNIT_1, EXAMPLE_ADC1_CHAN0, EXAMPLE_ADC_ATTEN, &adc1_cali_chan0_handle);
    bool do_calibration1_chan1 = example_adc_calibration_init(ADC_UNIT_1, EXAMPLE_ADC1_CHAN1, EXAMPLE_ADC_ATTEN, &adc1_cali_chan1_handle);

这里的 example_adc_calibration_init 是一个自定义的函数,用于初始化校准,这个函数可以直接拿来用。这个函数的定义如下:

c
static bool example_adc_calibration_init(adc_unit_t unit, adc_channel_t channel, adc_atten_t atten, adc_cali_handle_t *out_handle)
{
    adc_cali_handle_t handle = NULL;
    esp_err_t ret = ESP_FAIL;
    bool calibrated = false;

#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
    if (!calibrated) {
        ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting");
        adc_cali_curve_fitting_config_t cali_config = {
            .unit_id = unit,
            .chan = channel,
            .atten = atten,
            .bitwidth = ADC_BITWIDTH_DEFAULT,
        };
        ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle);
        if (ret == ESP_OK) {
            calibrated = true;
        }
    }
#endif

#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
    if (!calibrated) {
        ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting");
        adc_cali_line_fitting_config_t cali_config = {
            .unit_id = unit,
            .atten = atten,
            .bitwidth = ADC_BITWIDTH_DEFAULT,
        };
        ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle);
        if (ret == ESP_OK) {
            calibrated = true;
        }
    }
#endif

    *out_handle = handle;
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "Calibration Success");
    } else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) {
        ESP_LOGW(TAG, "eFuse not burnt, skip software calibration");
    } else {
        ESP_LOGE(TAG, "Invalid arg or no memory");
    }

    return calibrated;
}

6.开始一次性采校

c
static int adc_raw[2][10];
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN0, &adc_raw[0][0]));

这里获取的是原始值,存放在 adc_raw 里面。

7.计算实际的电压值

c
static int voltage[2][10];
ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc1_cali_chan0_handle, adc_raw[0][0], &voltage[0][0]));
ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, voltage[0][0]);

说明:

关于衰减系统的问题。根据理论计算当衰减系统为12时,ADC的参考电压是1100mV。此时计算得到的理论可测的最大电压为:

$$ V_{max} = 1100mV * 2^{12} = 4095mV $$

而实际上,测得到的最大电压为:2.8V左右。具体原因不是很清楚。因此在实际电路设计时,还要进行硬件上的分压,再接入ADC。最大的电压值,要根据实际情况进行测量后确定。以免造成不必要的问题。