【ESP32 idf ADC测量两路传感器(热敏&光敏)】

ADC

ADC介绍

ADC(ADC,Analog-to-Digital Converter) 全称为模拟-数字转换器,是一种用于将模拟信号转换为数字信号的模拟数字转换器。我们知道,模拟信号是连续的,其取值可以在一定范围内任意变化,如声音、光信号等。而数字信号则是离散的二进制信号,如计算机中的数据0和1,仅能取有限的值。

ADC的工作原理是将模拟信号通过采样转换为离散的数字信号,然后再通过量化编码等处理,最终得到对应的数字表示。ADC采样的频率越高,得到的数字信号就越接近原来的模拟信号,也就是保真度越高,但是需要更多的资源和计算功耗。
ADC 通常用于从外部模拟传感器中读取模拟信号,并将其转换为数字信号供嵌入式系统或计算机进行处理,例如测量温度、湿度、压力等物理量。

ADC的基本工作原理
采样:ADC通过采样(Sampling)将连续的模拟信号在特定的时间间隔上进行采样,得到一系列离散的模拟值。

量化:采样后的模拟信号被量化(Quantization)为有限个离散的数值。量化过程会引入一定的量化误差。

编码:量化后的数值被编码(Encoding)为二进制数,形成数字信号输出。

关键参数

  • 分辨率(Resolution):分辨率是指ADC输出的数字信号的位数。例如,8位、10位、12位、16位等。分辨率越高ADC的精度越高。例如,12位ADC的分辨率为2^12 = 4096,这意味着它可以将输入信号分为4096个不同的等级。

  • 采样率(Sampling Rate):采样率是指ADC每秒钟采样的次数,单位是赫兹(Hz)采样率越高,ADC能够捕捉的信号变化就越快。根据奈奎斯特采样定理,采样率至少要是输入信号最高频率的两倍,以防止混叠(Aliasing)。

  • 输入范围(Input Range):ADC能够接受的输入电压范围。例如,一些ADC的输入范围是0到3.3V或-1.5V到1.5V。

  • 信噪比(SNR, Signal-to-Noise Ratio):信噪比是输入信号功率与噪声功率的比值。较高的信噪比表示ADC能够更准确地测量输入信号而不受噪声干扰

  • 总谐波失真(THD, Total Harmonic Distortion):THD是输入信号的谐波失真的度量,较低的THD表示ADC对输入信号的失真较小

  • 无失码(No Missing Codes):无失码表示ADC在其转换范围内,每一个可能的输出代码都可以在某个输入电压范围内产生

ADC的类型

  • 逐次逼近寄存器(SAR, Successive Approximation Register)ADC:这种类型的ADC通过逐步逼近的方法,将输入信号与DAC生成的电压进行比较,逐步逼近最终的数字值。SAR ADC通常具有中等的分辨率和采样率,适用于很多通用应用。

  • ΔΣ(Delta-Sigma)ADC:ΔΣ ADC通过超采样和噪声整形来实现高分辨率。它们通常具有很高的分辨率,但采样率较低适用于高精度的测量。

  • 流水线(Pipeline)ADC:这种类型的ADC通过多级逐步逼近和并行处理实现高速和高分辨率。它们适用于高速信号处理,如视频和通信

  • 闪存(Flash)ADC:Flash ADC通过并行比较器将输入信号与所有可能的电压级别进行比较,实现非常高的采样率,但其分辨率和功耗较高

应用领域

  • 音频处理:如音频录音和数字音频工作站。
  • 传感器接口:如温度传感器、压力传感器和加速度计。
  • 通信:如无线电接收和数字通信。
  • 医疗设备:如心电图(ECG)和脑电图(EEG)。
  • 工业自动化:如过程控制和数据采集系统。

ESP32的ADC介绍

笔者使用的是ESP32-Wroom-32的开发板
在这里插入图片描述
ESP32-Wroom-32的通道如下图所示:
在这里插入图片描述
在这里插入图片描述

查阅其他资料时发现ESP32-S3的ADC有如下介绍:

而ESP32-S3 集成了两个 12 位 SAR ADC,每个ADC有10个通道,共支持 20 个模拟通道输入,可测量最多来自 20 个管脚的模拟信号以及内部电压等内部信号。其中,为了实现更低功耗,ESP32-S3 的 ULP 协处理器也可以在睡眠方式下测量电压,此时,可通过设置阈值或其他触发方式唤醒 CPU。

ADC可以转换的电压范围由VREF决定,对于ESP32-S3通常是0到3.3V,但需要注意的是,ESP32具体的最大额定输入电压可能略有不同,检查相应数据手册的具体信息非常重要,通常会建议使用衰减器(Attenuation)功能或者额外的硬件如电压分压器来保证输入电压在规定范围内。

ESP32-S3内部还带了一个温度传感器,用于生成一个随温度变化的电压。内部 ADC 将传感器电压转化为一个数字量,温度传感器的测量范围为–20 °C 到 110 °C。温度传感器适用于监测芯片内部温度的变化,该温度值会随着微控制器时钟频率或 IO 负载的变化而变化。一般来讲,芯片内部温度会高于外部温度。

ESP32-S3 的参数及其属性
在这里插入图片描述

使用ADC

包含相关头文件

#include "esp_adc_cal.h"
#include "driver/adc.h"

第一个是配置adc1的精度,esp32中一共有俩adc,分别是adc1和adc2,按理说我们都可以用。但是我们最好就是用adc1,每个adc有8个通道,所以一个也是够用的。

至于为什么不用adc2,这是因为adc2和WiFi是冲突的,而WiFi基本上是咱物联网的标配,因此为了避免冲突,咱就是用adc1。

配置ADC参数
通过调用函数adc1_config_width()adc1_config_channel_atten()配置所需精度衰减

adc1_config_width()

adc1_config_width 是 ESP32 中的 ADC1 模块的配置函数之一,它用于设置 ADC1 的精度(位数)。通过这个函数,你可以将 ADC1 的精度设置为 9 位、10 位、11 位或 12 位。 对应分辨率,分辨率越高ADC的精度越高。例如,12位ADC的分辨率为2^12 = 4096

void adc1_config_width(adc_bits_width_t width);

配置时如下参数:
在这里插入图片描述
其中 width 参数指定要设置的分辨率位数,它可以是以下值之一:

  • ADC_WIDTH_BIT_9: 将 ADC1 的精度设置为 9 位
  • ADC_WIDTH_BIT_10: 将 ADC1 的精度设置为 10 位
  • ADC_WIDTH_BIT_11: 将 ADC1 的精度设置为 11 位
  • ADC_WIDTH_BIT_12: 将 ADC1 的精度设置为 12 位

adc1_config_channel_atten()
adc1_config_channel_atten()是 ESP32 中的 ADC1 模块配置函数之一,它用于设置 ADC1 特定通道的衰减参数。衰减参数,衰减越大,可接受的电压越大。

void adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten);

第一个参数选择通道,我们知道ESP32-Wroom-32 ADC1都有8个通道,因此可选的有8个。

  • channel:要配置的 ADC1 通道,类型为 adc1_channel_t。

对应上图
在这里插入图片描述
在这里插入图片描述
第二个选择衰减参数。
atten 决定了 ADC 输入信号的电压范围,可选值有:

  • ADC_ATTEN_DB_0: 0 dB 衰减,输入电压范围为 0-1.1V。
  • ADC_ATTEN_DB_2_5: 2.5 dB 衰减,输入电压范围为 0-1.5V。
  • ADC_ATTEN_DB_6: 6 dB 衰减,输入电压范围为 0-2.2V。
  • ADC_ATTEN_DB_11: 11 dB 衰减,输入电压范围为 0-3.3V。
    在这里插入图片描述
    这个根据自己手上的传感器的电气参数来选择,不清楚的话就先选11db的,这样就算电压范围不一样也不会导致板子烧坏。

读取ADC的值

  1. 使用 adc1_get_raw 函数来获取 ADC 值。
    adc1_get_raw 是 ESP32 中的 ADC1 模块函数之一,用于以原始 12 位 ADC 值的形式读取 ADC1 的指定通道的测量值。
    函数原型如下:
int adc1_get_raw(adc1_channel_t channel);

在这里插入图片描述

代码

myADC.c

#include <string.h>
#include <stdio.h>
#include <esp_log.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#include "myADC.h"

#define DEFAULT_VREF    1100        // 默认参考电压,单位mV
static esp_adc_cal_characteristics_t *adc_chars; // 分配内存使用

#define myADC_heat_sensitive_channel      ADC_CHANNEL_6 // GPIO34 热敏传感器Ao输入
#define myADC_light_channel               ADC_CHANNEL_7 // GPIO35 光敏传感器Ao输入

#define AD_Value1_Channnel                myADC_heat_sensitive_channel // 重新定义一个, 为例后续更好的更改
#define AD_Value2_Channnel                myADC_light_channel // 重新定义

#define width                             ADC_WIDTH_BIT_12     // ADC分辨率 12位
#define atten                             ADC_ATTEN_DB_11      // ADC衰减   11 dB 衰减,输入电压范围为 0-3.3V。
#define unit                              ADC_UNIT_1           // ADC1 
#define NO_OF_SAMPLES                     128                  // 采样次数, 目的: 多次采样, 滤波



/**
 * @description: ADC初始化
 * @return {无}
 */
void myADC_Init() {
    adc1_config_width(ADC_WIDTH_BIT_12); // 12位分辨率
    adc1_config_channel_atten(AD_Value1_Channnel, atten); // 配置ADC通道
    adc1_config_channel_atten(AD_Value2_Channnel, atten); // 配置ADC通道
    adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t)); // 分配内存
    esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_chars); // 对ADC特性进行初始化
}


/**
 * @description: 获取传感器的AD值和电压值
 * @param {int16_t} *AD_Value1 第一个传感器的AD值的地址
 * @param {int16_t} *AD_Value2 第二个传感器的AD值的地址
 * @param {float*} Voltage1    第一个传感器的电压值的地址
 * @param {float*} Voltage2    第二个传感器的电压值的地址
 * @return {*}
 */
void myADC_GetAdAndVoltage_Value(int16_t *AD_Value1, int16_t *AD_Value2, float* Voltage1, float* Voltage2) {
    uint32_t adc_reading1 = 0;
    uint32_t adc_reading2 = 0;
    for (int i = 0; i < NO_OF_SAMPLES; i++) { // 多次采样, 滤波
        adc_reading1 += adc1_get_raw(AD_Value1_Channnel); // 采集热敏传感器Ad值
        adc_reading2 += adc1_get_raw(AD_Value2_Channnel); // 采集光照值
    }
    adc_reading1 /= NO_OF_SAMPLES; // 得到滤波后的数据
    adc_reading2 /= NO_OF_SAMPLES; // 得到滤波后的数据
    
    // esp_adc_cal_raw_to_voltage返回的是mV, 想得到单位V, 除以1000
    *AD_Value1 = (int16_t)adc_reading1; // 转换为int16_t类型
    *AD_Value2 = (int16_t)adc_reading2; // 转换为int16_t类型
    *Voltage1 = esp_adc_cal_raw_to_voltage(adc_reading1, adc_chars) / 1000.0; // 获取热敏传感器电压值
    *Voltage2 = esp_adc_cal_raw_to_voltage(adc_reading2, adc_chars) / 1000.0; // 获取光照电压值
}

myADC.h

#ifndef _MYADC__H
#define _MYADC__H
#include <stdint.h>
void myADC_Init();
// 获取ADC值和电压值
void myADC_GetAdAndVoltage_Value(int16_t *AD_Value1, int16_t *AD_Value2, float* Voltage1, float* Voltage2);



#endif

main.c

#include <stdio.h>
#include "myADC.h"
#include <freeRTOS/FreeRTOS.h>
#include <esp_log.h>


int16_t heat_sensitive_AdVal, light_AdVal;
float heat_sensitive_Voltage, light_Voltage;
void app_main(void)
{
    myADC_Init();
    while (1)
    {
        myADC_GetAdAndVoltage_Value(&heat_sensitive_AdVal, &light_AdVal, &heat_sensitive_Voltage, &light_Voltage);
        ESP_LOGI("main","热敏传感器的AD值: %d\t 光敏的AD: %d \n",heat_sensitive_AdVal,light_AdVal);
        ESP_LOGI("main","热敏传感器电压值: %.2f\t 光敏电压值: %.2f ",heat_sensitive_Voltage,light_Voltage);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }


}

项目结构
在这里插入图片描述
项目调试

在这里插入图片描述

  • 26
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

i want to舞动乾坤

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

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

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

打赏作者

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

抵扣说明:

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

余额充值