ADC
- ADC
- ESP32的ADC通道
- 衰减倍数
- 代码实现
- 精度问题
ADC
ADC(模拟-数字转换器),首先了解模拟信号和数字信号之间的差异。模拟信号是连续的,可以在其范围内取无限个离散值,例如声音、光线等。 数字信号则是离散的,具有一组有限数量的值,通常用于计算机和电子设备中的信息传输。ADC的作用是将模拟信号转换为数字信号,以便计算机或其他电子设备进行处理和分析。
ADC转换的过程分为两个重要步骤:采样和量化。ADC的输入是模拟信号。当输入的模拟信号被采样时,其值将在设定的时间间隔(采样周期)内以等间隔的方式进行抽样。这样就可以将连续的模拟信号转换为一系列等间隔的采样值。接下来,将每个采样值映射到最接近的离散值(也称为“量化”),并且该离散值将作为ADC的输出。量化可以根据设定的分辨率完成,分辨率表示可以区分的离散值的数量。例如,12位ADC具有2^12(即4096)个可区分的离散值。此外,ADC提供选择衰减器(Attenuator)的功能,该衰减器可以对信号进行放大或消减,以确保输入信号处于ADC可接受的幅度范围内。
ESP32的ADC通道
ESP32具有两个集成的ADC,分别称为ADC1和ADC2。两个12位的ADC,其中ADC1(8个通道,连接到GPIO 32-39)和ADC2(10个通道,连接到GPIO 0、2、4、12-15和25-27)
衰减倍数
不同的衰减倍数对应不同的检测电压范围。
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
代码实现
#include <esp_adc_cal.h>
#include <driver/adc.h>
#define DEFAULT_VREF 1100 // 默认1.1V的参考电压
#define NO_OF_SAMPLES 64 // ADC采样次数
#define ADC_WIDTH ADC_WIDTH_12Bit // ADC 12位宽度
#define ADC_ATTEN ADC_ATTEN_6db // 6dB衰减器
#define ADC_PIN ADC1_CHANNEL_4
esp_adc_cal_characteristics_t *adc_chars;
void setup() {
Serial.begin(115200);
adc1_config_width(ADC_WIDTH); // 设置ADC为12位宽度
adc1_config_channel_atten(ADC_PIN, ADC_ATTEN); // 配置ADC通道为6dB衰减器
// 使用eFuse校准ADC,并获取校准值
adc_chars = (esp_adc_cal_characteristics_t *) malloc(sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN, ADC_WIDTH, DEFAULT_VREF, adc_chars);
}
void loop() {
uint32_t adc_reading = 0;
for (int i = 0; i < NO_OF_SAMPLES; i++) {
adc_reading += adc1_get_raw((adc1_channel_t) ADC_PIN);
delay(1);
}
adc_reading /= NO_OF_SAMPLES;
uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
Serial.print("ADC Reading: ");
Serial.print(adc_reading);
Serial.print("\tVoltage: ");
Serial.println(voltage);
delay(1000);
}
说明:本次测量时IO34已做分压处理
adc_chars = new esp_adc_cal_characteristics_t; // 新分配一个存储ADC校准值的指针
esp_adc_cal_characterize(ADC_UNIT_2, ADC_ATTEN_DB_11, ADC_WIDTH, DEFAULT_VREF, adc_chars); // 校准ADC2
在ESP32上使用ADC读取模拟电压时,需要先进行ADC的校准,确保输出结果的准确性和稳定性。在校准过程中,需要使用ESP-IDF中的esp_adc_cal_characterize()
函数对ADC进行校准。该函数需要传入ADC的一些基本参数和一个指向存储校准值的首地址赋值给adc_chars
指针。sizeof(esp_adc_cal_characteristics_t)
获取esp_adc_cal_characteristics_t
结构体的大小,malloc()
函数会返回一个指向分配的内存块的首地址的指针。这样就成功为存储ADC校准值的结构体分配了一段内存,可供后续的ADC校准过程使用。
接下来,esp_adc_cal_characterize()
函数将使用指定的参考电压DEFAULT_VREF
和衰减ADC_ATTEN
以及ADC的位宽ADC_WIDTH
进行ADC的校准。校准完成后,esp_adc_cal_characterize()
函数将会返回esp_adc_cal_value_t
类型的校准值类型,这个值表示所选的ADC_UNIT
和ADC_ATTEN
组合所需要的校准选项。同时,校准过程得到的校准值会被保存在之前动态分配内存块中的adc_chars
指针所指向的结构体中,在后续的代码中可以直接使用校准值进行ADC读取和转换。
总而言之,使用malloc()
函数为存储ADC校准值的结构体变量分配内存,并使用esp_adc_cal_characterize()
函数为ADC进行校准,可以确保ADC读取的准确性和稳定性。esp_adc_cal_characteristics_t
结构体的指针。
在上述代码中,通过使用malloc()
函数在堆内存中动态分配了一段大小为esp_adc_cal_characteristics_t
结构体大小的内存,同时将该内存的
精度问题
ESP32的ADC测试存在精度问题!!!解决方法:分段算出偏差,然后进行软件补偿,或者使用ESP源码。由于开发问题补偿代码不贴出参考了。
可参考:https://zhuanlan.zhihu.com/p/540437244
参考链接:https://www.jianshu.com/p/7739b143b41d