ESP32-C3 ADC
简介
ADC(模数转换器)是将模拟信号转换为数字信号的电子元件。ESP32-C3 内置了多个 ADC 通道,可以用于测量各种模拟信号,如电压、电流、温度等。
ADC 通道
ESP32-C3 有 6 个 ADC 通道,分别为 ADC1 和 ADC2。ADC1 有 5 个通道,ADC2 有 1 个通道。每个通道都可以测量不同的模拟信号。
信号名称 | 通道编号 | ADC 选择 |
---|---|---|
GPIO0 | 0 | SAR ADC1 |
GPIO1 | 1 | SAR ADC1 |
GPIO2 | 2 | SAR ADC1 |
GPIO3 | 3 | SAR ADC1 |
GPIO4 | 4 | SAR ADC1 |
GPIO5 | 0 | SAR ADC2 |
注意:
通道与引脚的对应关系是固定的,不能更改。
ADC 编程
在 ESP32-C3 芯片中,ADC采样可能于制造工艺的原因,其ADC采样的结果会有偏差,这个偏差值在芯片制造时进行了校准。校准后的参数保存在了efuse中了。我们在实际使用时,需要参考这些参数,再对所采样的值进行校准后计算出实际的电压值。
在实际的编程中,我们会使用一个 ESP-IDF 中的组件 esp_adc
来进行 ADC 采样。这个组件提供了一些 API 函数,可以方便地进行 ADC 采样。
1.引入组件库
所以我们在实际的开如,需要引入这个库组件。方法时在 CMakeLists.txt
中添加以下内容:
idf_component_register(SRCS "adc.c"
PRIV_REQUIRES esp_adc
INCLUDE_DIRS "")
PRIV_REQUIRES esp_adc
表示我们使用的是 esp_adc
这个库组件。
2.引入头文件
#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值,表示使用默认值。
#define EXAMPLE_ADC1_CHAN0 ADC_CHANNEL_0
#define EXAMPLE_ADC1_CHAN1 ADC_CHANNEL_1
#define EXAMPLE_ADC_ATTEN ADC_ATTEN_DB_12
3.初始化 ADC
//-------------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
//-------------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 的衰减系数和采样位数。衰减系统可能的取值为:
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;
采样位数可能的取值为:
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中的参数,来生成一个用于校准的句柄。
//-------------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
是一个自定义的函数,用于初始化校准,这个函数可以直接拿来用。这个函数的定义如下:
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.开始一次性采校
static int adc_raw[2][10];
ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN0, &adc_raw[0][0]));
这里获取的是原始值,存放在 adc_raw 里面。
7.计算实际的电压值
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。最大的电压值,要根据实际情况进行测量后确定。以免造成不必要的问题。