ESP32入门六(读取引脚的模拟信号[2]:信号出现误差的原因)

在之前的章节中,我们测试了用ESP32来接收模拟电压信号,在测试中,读取到的数据与现实存在一定的误差,在这一篇中,我们尝试了解出现误差的原因和解决方法。

对于出现的误差,有多种软件和硬件方面的原因:

一、官方设置原因

二、代码原因

三、硬件原因

四、电源原因


我们对应这几个原因,一步一步来测试并尝试解决。

我们所使用的ESP32版本有许多(esp32,esp32-s2,esp32-c3,esp32-s3等),对于ADC的更新和优化也一直在进行。在本系列章节中所使用的版本为esp32,而该版本的ADC功能在使用过程中,体现是比较差的一个版本。

我们在官方文档中可以查到该版本的ADC功能的量程

ADC_ATTEN_DB_0      100 mV ~ 950 mV      (0.1V~0.95V)
ADC_ATTEN_DB_2_5   100 mV ~ 1250 mV   (0.1V~1.25V)
ADC_ATTEN_DB_6      150 mV ~ 1750 mV    (0.15V~1.75V)
ADC_ATTEN_DB_11    150 mV ~ 3100 mV    (0.15V~3.1V)

也就是说,在默认设置下,我们可以读取的电压范围为0.15V~3.1V,但是我们在上一章中所使用的是3.3V的引脚,也就是说,当电压为3.1V时,我们读取到的数据已经等于4095,但电压继续上升时,我们读取到的数据并不会继续增加。

我们可以用代码来测试这个现像,我们用ESP32的DAC功能来生成一个电压,同时用ADC功能来读取这个生成的电压,测试生成的电压和读取的电压是否相同。

#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.3  / 255;    //DAC值转为电压值
  Serial.print("vout = ");
  Serial.print(vout);                     //串口输出当前输出的电压值
  dacWrite(25,dac_value);                   //25号引脚输出对应电压

  int adc_value = analogRead(4);            //4号引脚读取25号引脚输出的模拟值
  float vin = (adc_value*3.3)  / 4095;      //读取到的数据转为电压值
  Serial.print(" | ");
  Serial.print("vin = ");
  Serial.println(vin);                      //串口输出当前输入的电压值
  delay(1000);
}

 查看串口输出

我们可以观察到

当输出的电压到达0.06V时,读取到的电压为0.01V。误差为0.06

在观察过程中,误差慢慢增加,当输出电压到达2.47V时,读取到的电压为2.12V,误差达到最大误差值,为0.35。

之后,误差慢慢减少,当输出电压到达3.30V时,读取到的电压为3.25V,误差为0.05。

这时,我们发现,这与官方文档所说明的量程为0.15V~3.10V的又出现了偏差。


所以,我们继续尝试用另一个函数:analogReadMillivolts()来读取4号引脚的电压:

#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.3  / 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);
}

读取的结果同样并不完美,同样出现误差的变化,但对比之前,误差已经在一定的范围内

当读取到的电压到达3.1V时,超量了0.04V,误差最大为0.14。

至此,我们大概已经可以了解到,在代码层面出现误差的原因有两点:

一、官方设置的量程问题

二、与analogRead()相比较,使用analogReadMillivolts()函数能更精确地读取对应的电压值。

        我们在官方文档中详细地了解一下这两个函数:ADC — Arduino-ESP32 2.0.14 documentation

analogRead()函数的作用是用于读取指定引脚的ADC值,返回的结果未经过校准。

        

analogReadMillivolts()函数的作用是用于读取指定引脚的ADC值,并返回转换为以毫伏为单位的校准结果。

至此,我们在本章中已经了解了软件方面导致数据出现误差的原因,在下一章中,我们将介绍在硬件方面导致数据出现误差的原因。

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要将ESP32和PCM1808配合使用读取模拟信号,您需要: 1. 将PCM1808的模拟输出信号连接到ESP32的I2S输入引脚上。在ESP32中,有两组I2S输入引脚,分别是I2S0和I2S1。您可以根据需要选择其中一组。 2. 配置I2S接口的参数,包括采样率、数据位宽、通道数等。可以使用`i2s_config_t`结构体来设置这些参数。 3. 配置I2S接口的时钟。ESP32可以使用内部时钟或外部时钟。如果使用外部时钟,需要将时钟信号连接到ESP32的GPIO引脚上。 4. 初始化I2S接口。可以使用`i2s_driver_install`函数来初始化I2S接口。 5. 启动I2S接口。可以使用`i2s_start`函数来启动I2S接口。 6. 使用`i2s_read`函数从I2S接口读取PCM数据。可以使用`i2s_read_bytes`函数将PCM数据读取到缓冲区中。 以下是一个简单的示例代码,演示了如何在ESP32上配合PCM1808读取模拟信号: ```c #include "driver/i2s.h" #define I2S_NUM I2S_NUM_0 #define BLOCK_SIZE 1024 void app_main() { i2s_config_t i2s_config = { .mode = I2S_MODE_MASTER | I2S_MODE_RX, .sample_rate = 44100, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, .communication_format = I2S_COMM_FORMAT_STAND_I2S, .dma_buf_count = 8, .dma_buf_len = BLOCK_SIZE, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .use_apll = false, .tx_desc_auto_clear = false, .fixed_mclk = 0 }; i2s_pin_config_t pin_config = { .bck_io_num = GPIO_NUM_26, .ws_io_num = GPIO_NUM_25, .data_out_num = I2S_PIN_NO_CHANGE, .data_in_num = GPIO_NUM_22 }; i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); i2s_set_pin(I2S_NUM, &pin_config); i2s_start(I2S_NUM); while (1) { static uint8_t buffer[BLOCK_SIZE]; i2s_read(I2S_NUM, buffer, BLOCK_SIZE, portMAX_DELAY); // 处理PCM数据 } } ``` 在此示例代码中,我们将PCM1808的模拟输出信号连接到GPIO22引脚上,将I2S输入接口配置为I2S0,以16位的方式读取PCM数据。每次从I2S接口读取到的数据块大小为1024字节。通过修改`pin_config`结构体中的`data_in_num`参数,可以将I2S输入引脚设置为其他GPIO引脚上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

字节狂徒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值