22-ESP32-S3模数转换器(ADC)

ESP32-S3模数转换器(ADC)

什么是模数转换器(ADC)🔍?


模数转换器(ADC)是一种将模拟信号(如电压)转换为数字信号的设备。在ESP32-S3中,ADC用于将模拟电压转换为数字值,以便微控制器可以处理。

ADC 转换器可分为:

  • 并行比较型A/D 转换器(FLASH ADC)
  • 逐次比较型A/D 转换器(SAR ADC)
  • 双积分式A/D 转换器(Double Integral ADC)

ESP32-S3中集成了两个SAR ADC

A/D 转换过程通常为 4 步:采样、保持、量化和编码:
在这里插入图片描述

  1. 采样:在这个阶段,连续的模拟信号被转换为离散的信号。这是通过在特定的时间间隔内测量信号的值来完成的。

  2. 保持:在这个阶段,采样值被“保持”或固定,以便进行下一步的量化。这是必要的,因为量化过程需要一定的时间,而我们不希望在这个过程中输入信号发生变化。

  3. 量化:在这个阶段,保持的采样值被近似为一组预定义的离散值。这是通过将输入信号的范围划分为一组小的区间(每个区间对应一个数字值)来完成的。

  4. 编码:在这个阶段,量化的值被转换为数字二进制代码,以便于数字系统处理。

这四个步骤共同构成了模数转换的过程,使得模拟信号可以被数字系统处理和理解。

衰减值和分辨率的概念🎊


衰减值

衰减值(Attenuation)在模数转换器(ADC)中,指的是在将模拟信号送入ADC进行转换之前,通过电子电路(如分压器)有意降低信号幅度的过程。这样做主要是为了匹配ADC的输入范围,确保信号不会超过ADC的最高可测量电压(满量程电压)。如果原始信号的电压范围超过了ADC的输入电压限制,不进行衰减可能会导致信号失真或者损坏ADC。

对于衰减值11dB意味着信号功率或电压幅度减少大约一半。在分贝(dB)的表达中,功率衰减遵循公式:

dB = 10 ⋅ log ⁡ 10 ( P 1 P 2 ) \text{dB} = 10 \cdot \log_{10} \left( \frac{P_1}{P_2} \right) dB=10log10(P2P1)

至于电压衰减,鉴于功率与电压平方成正比 P ∝ V 2 P \propto V^2 PV2,相应的转换公式为:

dB = 20 ⋅ log ⁡ 10 ( V 1 V 2 ) \text{dB} = 20 \cdot \log_{10} \left( \frac{V_1}{V_2} \right) dB=20log10(V2V1)

因此,若信号遭受11dB的衰减,这意指着电压幅度减小约 1 0 11 20 \sqrt{10^{\frac{11}{20}}} 102011 倍,等价于更直观的百分比形式,即信号维持了原初幅度的大约79.4%,或者说损失了20.6%。更精确地,

V 2 = V 1 ⋅ 1 0 − 11 20 ≈ 0.891 V 1 V_2 = V_1 \cdot 10^{-\frac{11}{20}} \approx 0.891V_1 V2=V11020110.891V1

因此,经历11dB衰减的信号,其电压水平将减至初始值的约89.1%,相应地,电压幅度减少了大约10.9%。

分辨率

在模数转换器(ADC)领域,分辨率是指ADC能够区分输入模拟信号细微差异的能力,即能够检测的最小电压变化量。简而言之,它体现了ADC输出数字信号时的精度。

分辨率通常由ADC的位数来表述。一个N位的ADC能够输出 2 N 2^N 2N个不同的数字量。例如,一个8位的ADC能够输出从0到255即 ( 2 8 − 1 ) (2^8 - 1) (281) 的数字值,而一个12位的ADC则能输出0到4095即 ( 2 12 − 1 ) (2^{12} - 1) (2121) 的值。这意味着,12位的ADC相比8位ADC,在相同的电压范围内能够提供更精细的量化。

分辨率与实际电压的对应关系可通过以下公式计算:
分辨率 = 满量程电压 2 N − 1 \text{分辨率} = \frac{\text{满量程电压}}{2^N - 1} 分辨率=2N1满量程电压
假设一个ADC的工作电压范围是0至3.3V,对于一个12位的ADC:
分辨率 = 3.3 V 4095 ≈ 0.000806 V 或者 0.806 m V \text{分辨率} = \frac{3.3V}{4095} \approx 0.000806V 或者 0.806mV 分辨率=40953.3V0.000806V或者0.806mV
这意味着,如果输入电压有任何大于0.806毫伏的变化,12位的ADC就能检测到并反映在输出的数字值上。因此,高分辨率ADC适合用于需要高度精确测量的应用场景,如精密仪器、传感器读数或是音频处理等领域。

ESP32-S3的ADC特性


ESP32-S3 集成了两个 12 位 SAR(逐次逼近寄存器) ADC,ADC1 和 ADC2,支持20 个模拟通道输入。这 20个模拟通道输入对应着具体的 IO。

ADC1型:

  • 10 通道:GPIO1 - GPIO10

ADC2型:

  • 10 通道:GPIO11 - GPIO20

ESP32-S3的ADC模块的分辨率为12位,所以AD转换后的值范围为0~4095。由于ESP32-S3的工作电压为3.3V,所以当AD值为4095时,对应的电压为3.3V;当AD值为0时,对应的电压为0V。

这里的关系可以用一个简单的公式来表示,即:

引脚输入的电压 = 引脚 A D 的值 4095 × 3.3 V 引脚输入的电压 = \frac{引脚AD的值}{4095} \times 3.3V 引脚输入的电压=4095引脚AD的值×3.3V

如何使用ESP32-S3的ADC


1️⃣配置 ADC

该函数用于配置 ADC 各项参数,其函数原型如下所示:

esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config)

该函数的形参描述如下:

形参描述
config指向 ADC 配置结构体的指针,需自行定义,并根据 ADC 的配置参数填充结构体中的成员变量

该函数的返回值描述如下:

返回值描述
ESP_OK返回:0,配置成功
ESP_ERR_INVALID_ARG无效参数
ESP_ERR_INVALID_STATE驱动程序状态无效

该函数使用 adc_digi_configuration_t 类型的结构体变量传入 ADC 外设的配置参数,该结构体的定义如下所示:

typedef struct {
    bool conv_limit_en;
    uint32_t conv_limit_num;
    uint32_t pattern_num;
    adc_digi_pattern_config_t *adc_pattern;
    uint32_t sample_freq_hz;
    adc_digi_convert_mode_t conv_mode;
    adc_digi_output_format_t format;
} adc_digi_configuration_t;

该函数的使用示例如下:

#include "driver/gpio.h"

void example_fun(void)
{
    adc_digi_pattern_config_t adc1_digi_pattern_config; // 定义 ADC1 的模式配置结构体
    adc_digi_configuration_t adc1_init_config; // 定义 ADC1 的初始化配置结构体

    /* 配置 ADC1 */
    adc1_digi_pattern_config.atten = ADC_ATTEN_DB_11; // 设置衰减为 11dB
    adc1_digi_pattern_config.channel = ADC_ADCX_CHY; // 设置通道为 ADC_ADCX_CHY
    adc1_digi_pattern_config.unit = ADC_UNIT_1; // 设置单元为 ADC_UNIT_1
    adc1_digi_pattern_config.bit_width = ADC_BITWIDTH_12; // 设置位宽为 12 位
    adc1_init_config.adc_pattern = &adc1_digi_pattern_config; // 将 ADC1 的模式配置结构体赋值给初始化配置结构体的 adc_pattern 成员
    adc_digi_controller_configure(&adc1_init_config); // 调用 adc_digi_controller_configure 函数配置 ADC 数字控制器
}

当然,以下是整理后的格式:

2️⃣读取 ADC 原始数据

该函数用于读取 ADC 原始数据,其函数原型如下所示:

int adc1_get_raw(adc1_channel_t channel);

该函数的形参描述如下:

形参描述
channelADC 通道

该函数的返回值描述如下:

返回值描述
-1读取失败
其他值ADC 的原始数值

该函数的使用示例如下:

uint32_t adc_get_result_average(uint32_t ch, uint32_t times)
{
    uint32_t temp_val = 0; // 定义一个临时变量用于存储 ADC 读取的值
    uint8_t t;

    for (t = 0; t < times; t++) // 循环 times 次
    {
        temp_val += adc1_get_raw(ch); // 读取 ADC 的原始值并累加到 temp_val
        vTaskDelay(5); // 延时 5ms
    }

    return temp_val / times; // 返回平均值
}

程序设计 💻


首先配置ADC以从通道7(即GPIO8)读取电压,然后将读取到的电压值打印到串口。

#include "driver/adc.h"
#include "esp_adc_cal.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

#define ADC_CHANNEL ADC_CHANNEL_7 // GPIO8
#define ADC_ATTEN ADC_ATTEN_DB_11
#define ADC_UNIT ADC_UNIT_1
#define ADC_WIDTH ADC_WIDTH_BIT_12
#define NUM_SAMPLES 64 // 多次采样
#define TAG "ADC"

void example_fun(void)
{
    adc_digi_pattern_config_t adc1_digi_pattern_config; // 定义 ADC1 的模式配置结构体
    adc_digi_configuration_t adc1_init_config; // 定义 ADC1 的初始化配置结构体

    adc1_digi_pattern_config.atten = ADC_ATTEN_DB_11; // 设置衰减为 11dB
    adc1_digi_pattern_config.channel = ADC_CHANNEL; // 设置通道为 ADC_CHANNEL
    adc1_digi_pattern_config.unit = ADC_UNIT_1; // 设置单元为 ADC_UNIT_1
    adc1_digi_pattern_config.bit_width = ADC_BITWIDTH_12; // 设置位宽为 12 位
    adc1_init_config.adc_pattern = &adc1_digi_pattern_config; // 将 ADC1 的模式配置结构体赋值给初始化配置结构体的 adc_pattern 成员

    adc_digi_controller_configure(&adc1_init_config); // 调用 adc_digi_controller_configure 函数配置 ADC 数字控制器
}

uint32_t adc_get_result_average(uint32_t ch, uint32_t times)
{
    uint32_t temp_val = 0; // 定义一个临时变量用于存储 ADC 读取的值
    uint8_t t;

    for (t = 0; t < times; t++) // 循环 times 次
    {
        temp_val += adc1_get_raw(ch); // 读取 ADC 的原始值并累加到 temp_val
        vTaskDelay(5); // 延时 5ms
    }

    return temp_val / times; // 返回平均值
}

void app_main(void)
{
    example_fun(); // 配置 ADC

    while (1) // 无限循环
    {
        uint32_t voltage = adc_get_result_average(ADC_CHANNEL, NUM_SAMPLES); // 读取 ADC 的平均值
        ESP_LOGI(TAG, "平均ADC读数: %d", voltage); // 将 ADC 的平均值打印到串口
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延时 1s
    }
}

总结

参考资料
正点原子DNESP32S3 开发板教程-IDF 版
乐鑫ESP32-IDF

  • 21
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你好!以下是一个简单的ESP32-S3ADC检测例程: ```C #include <stdio.h> #include "esp_adc_cal.h" #include "esp_log.h" #include "esp_system.h" #include "driver/adc.h" #define DEFAULT_VREF 1100 #define NO_OF_SAMPLES 64 static const char *TAG = "ADC"; void app_main() { // 配置ADC adc1_config_width(ADC_WIDTH_BIT_12); adc1_config_channel_atten(ADC_CHANNEL_0, ADC_ATTEN_DB_11); // 计算ADC参考电压 esp_adc_cal_characteristics_t adc_chars; esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, DEFAULT_VREF, &adc_chars); // 读取ADC值并打印 while (1) { uint32_t adc_reading = 0; for (int i = 0; i < NO_OF_SAMPLES; i++) { adc_reading += adc1_get_raw((adc1_channel_t)ADC_CHANNEL_0); } adc_reading /= NO_OF_SAMPLES; uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, &adc_chars); ESP_LOGI(TAG, "Raw: %d\tVoltage: %dmV", adc_reading, voltage); vTaskDelay(pdMS_TO_TICKS(1000)); } } ``` 这个例程使用了ESP-IDF框架来进行ADC的配置和读取。首先,我们通过`adc1_config_width`函数将ADC的位宽设置为12位,然后使用`adc1_config_channel_atten`函数将ADC通道设置为通道0,并设置增益为11dB。 接下来,我们使用`esp_adc_cal_characterize`函数计算ADC的参考电压,并将结果存储在`adc_chars`结构体中。 在主循环中,我们使用`adc1_get_raw`函数来读取ADC的原始值,并将它们累加起来。然后,我们对累加值求平均值,得到一个稳定的ADC读数。最后,我们使用`esp_adc_cal_raw_to_voltage`函数将原始值转换为电压,并打印出来。 请注意,这个例程仅仅是一个简单的示例,你可以根据自己的需求进行修改和扩展。希望能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宁子希

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

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

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

打赏作者

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

抵扣说明:

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

余额充值