在之前的文章中,我们介绍了ESP32在读取模拟信号时出现的误差的软件方面原因,在这一篇中,将会介绍并测试由于硬件或其它方面导致数据出现误差的原因。
一、厂商原因
首先,我们需要知道,在每块EPS32中,在出厂时都带有一个ADC的基准值,我们可以用两种方法来查看到该基准值:
1、安装esptool工具来查看基准值
我们需要下载并安装python:
Python Release Python 3.12.1 | Python.org
选择合适你电脑的版本,下载并安装,在安装过程中,注意选择安装pip工具和勾选加入环境变量。
安装完成后,打开CMD。我们输入命令:
pip install esptool
等待安装完成
安装安成后我们输入命令:
espefuse.exe --port COM5 adc_info
注意这里的COM5需要对应你自已ESP32在电脑上的端口号
我们可以得到adc的校准值。
2、用esp_adc_cal_characterize()函数获取ADC特性
函数:
esp_adc_cal_characterize()
作用:将描述 ADC 在特定衰减条件下的特性,并以[y=coeff_a * x + coeff_b]的形式生成ADC电压曲线
格式:
esp_adc_cal_value_t esp_adc_cal_characterize(
adc_unit_t adc_num,
adc_atten_t atten,
adc_bits_width_t bit_width,
uint32_t default_vref,
esp_adc_cal_characteristics_t *chars
)
参数:
adc_num -ADC特征编码(ADC_UNIT_1 or ADC_UNIT_2)可以在官方文档中的引脚定义中查看
atten -衰减值(ADC_ATTEN_DB_0 / ADC_ATTEN_DB_2_5 / ADC_ATTEN_DB_6 / ADC_ATTEN_DB_11)
bit_width -位宽设置(ADC_WIDTH_BIT_9 / ADC_WIDTH_BIT_10 / ADC_WIDTH_BIT_11 / ADC_WIDTH_BIT_12 / ADC_WIDTH_MAX)
default_vref -默认ADC基准电压(mV)
*chars -用于存储ADC特征的空结构指针
返回:
ESP_ADC_CAL_VAL_EFUSE_VREF - ADC特性为eFuse中存储的Vref值
ESP_ADC_CAL_VAL_EFUSE_TP -特性为两点的值(仅用于线性模式)
ESP_ADC_CAL_VAL_DEFAULT_VREF -特性为默认Vref值
代码:
#include "esp_adc_cal.h"
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(500);
float vref_value;
esp_adc_cal_characteristics_t adcChar;
esp_adc_cal_value_t cal_mode = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adcChar);
if(cal_mode == ESP_ADC_CAL_VAL_EFUSE_VREF){
vref_value = adcChar.vref; // 获取参考电压
Serial.print("参考电压为:");
Serial.println(vref_value);
}else if(cal_mode == ESP_ADC_CAL_VAL_DEFAULT_VREF){
Serial.println("默认参考电压");
}
}
void loop() {
// put your main code here, to run repeatedly:
}
运行后串口可以接收到设备的参考电压,当前测试的板子参考电压为1149
这个基准电压之所以和参考电压1100V有所误差,是因为每个板子在生产过程中,因为工艺 原因,导致内部电压和参考电压出现误差,所以,在出 厂时,把这个误差值写入到板子,以便使用者可以测量和消除这个误差, 这个基准值可以生成特性曲线,以反映特定 ESP32 芯片 ADC 基准电压的变化,在上一章中所用到的analogReadMillivolts()函数,就是利用这个基准值来消除读取数据时产生的误差。
二、电压误差
大多数情况下,在使用或测试ESP32的过程中,很少人会用到专业的电源来输出。同时,也因为工艺的原因,所以,我们如果用万用表测量3V3引脚时,很可能测量出来的数据并非3.3V。比如本文 中所用的板子是连接到电脑USB接口上的,在所有引脚都悬空的情况下,用万用表测量到的3v3引脚的电压为3.2V。而在另一块板子上测量到的电压为3.32V。在这种情况下,不管是电源的原因还是生产工艺的原因,都会对读取到的数据造成误差。我们同样以上一章中所用的板子,以同样的代码,但生成的电压设置为3.2V来再次测试读取到的数据:
我们把代码中的
float vout = (dac_value) * 3.3 / 255;
//改为
float vout = (dac_value) * 3.2 / 255;
#include <esp32-hal-adc.h>
uint8_t dac_value = 0; //DAC值,2^8长度
void setup() {
Serial.begin(115200);
}
void loop() {
dac_value++; //DAC值累加
float vout = (dac_value) * 3.2 / 255; //DAC值转为电压值
Serial.print("vout = ");
Serial.print(vout); //串口输出当前输出的电压值
dacWrite(25,dac_value); //25号引脚输出对应电压
float vin = analogReadMillivolts(4)/1000.0; //4号引脚读取25号引脚的电压值
Serial.print(" | ");
Serial.print("vin = ");
Serial.print(vin); //串口输出当前输入的电压值
Serial.print(" | ");
Serial.print("deviation = ");
Serial.println(vout - vin); //串口输出当前输出与输入的误差
delay(100);
}
可以观察到,误差对比上一章进一步减少了