12. ADC

news/2025/3/20 23:00:51/文章来源:https://www.cnblogs.com/FlurryHeart/p/18784157

一、ADC简介

  生活中接触到的大多数信息是醉着时间连续变化的物理量,如声音、温度、压力等。表达这些信息的电信号,称为 模拟信号(Analog Signal)。为了方便存储、处理,在计算机系统中,都是数字 0 和 1 信号,将模拟信号(连续信号)转换为数字信号(离散信号)的器件就叫模数转换器(Analog-to-Digital Convert,ADC)。

  ADC 转换器可分为:并行比较型 A/D 转换器(FLASH ADC)、逐次比较型 A/D 转换器(SARADC)和 双积分式 A/D 转换(Double Integral ADC)。

  A/D 转换过程通常为 4 步:采样保持量化编码,如下图所示。

AD转换过程图

  • 采样:把时间连续变化的信号变换为时间离散的信号。
  • 保持:保持采样信号,使有充分时间转换为数字信号。
  • 量化:把采样保持电路的输出信号用单位量化电压的整数倍表示。
  • 编码:把量化的结果用二进制代码表示。

采样和保持通常是在采样-保持电路中完成,量化和编码通常在 ADC 数字编码电路中完成。

二、ADC外设简介

  在 ESP32 S3 中,模数转换器(ADC)比较输入的模拟电压和参考电压,以确定每一位数字输出结果。ESP32 S3 设计的 ADC 参考电压为 1100 mV。然而,不同芯片的真实参考电压可能会略有变化,范围在 1000 mV 到 1200 mV 之间。

  ESP32 S3 集成了两个 12 位 SARADC,ADC1 和 ADC2,支持 20 个模拟通道输入。这 20 个模拟通道输入对应着具体的 IO,并不是随意的 IO 都有模拟输入功能,具备模拟输入功能的引脚如下表所示。

具备模拟输入功能的引脚

  ESP32 S3 的 ADC 模块的分辨率为 12 位,所以 AD 转换后的值范围为 0 ~ 4095。由于 ESP32 S3 的工作电压为 3.3V,所以当 AD 值为 4095 时,对应的电压为 3.3V;当 AD 值为 0 时,对应的电压为 0V。对于 AD 值和电压值,这里就会有一个简单的关系,如下所示。

\[V_{引脚电压} = \frac{引脚的 AD 值}{2^{12}} * 3.3V \]

二、ADC常用函数

  ESP-IDF 提供了一套 API 来配置 ADC。要使用此功能,我们需要在 CMakeLists.txt 文件中导入 esp_timer 依赖库,然后还需要导入必要的头文件:

# 注册组件到构建系统的函数
idf_component_register(# 依赖库的路径REQUIRES esp_adc
)

  如果要使用 ADC 的单次转换,我们需要导入以下头文件。

#include "esp_adc/adc_oneshot.h"

2.1、配置ADC单次转换

  我们可以使用 adc_oneshot_new_unit() 函数用于 配置 ADC 单次转换,其函数原型如下所示:

/*** @brief 配置ADC单次转换* * @param init_config ADC单次转换配置结构体指针* @param ret_unit 保存ADC句柄* @return esp_err_t ESP_OK表示配置成功,其它表示配置失败*/
esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, adc_oneshot_unit_handle_t *ret_unit);

  形参 init_config指向 ADC 单次转换配置结构体的指针,它的定义如下:

typedef struct 
{adc_unit_t unit_id;             // 使用的ADC单元adc_oneshot_clk_src_t clk_src;  // 时钟源adc_ulp_mode_t ulp_mode;        // ADC controlled by ULP, see `adc_ulp_mode_t`
} adc_oneshot_unit_init_cfg_t;

  成员 unit_id使用的 ADC 单元,它的可选值如下:

typedef enum 
{ADC_UNIT_1,        ///< SAR ADC 1ADC_UNIT_2,        ///< SAR ADC 2
} adc_unit_t;

  成员 clk_srcADC 的时钟源,它的可选值如下:

typedef enum 
{ADC_RTC_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST,      /*!< Select RC_FAST as the source clock */ADC_RTC_CLK_SRC_DEFAULT = SOC_MOD_CLK_RC_FAST,      /*!< Select RC_FAST as the default clock choice */
} soc_periph_adc_rtc_clk_src_t;typedef soc_periph_adc_rtc_clk_src_t     adc_oneshot_clk_src_t; 

2.2、配置ADC单次转换的通道

  我们可以使用 adc_oneshot_config_channel() 函数 配置 ADC 单次转换的通道,它的原型如下:

/*** @brief 配置ADC单次转换的通道* * @param handle ADC句柄* @param channel 使用的ADC通道* @param config ADC单次转换通道配置的结构体指针* @return esp_err_t ESP_OK表示配置成功,其它表示配置失败*/
esp_err_t adc_oneshot_config_channel(adc_oneshot_unit_handle_t handle, adc_channel_t channel, const adc_oneshot_chan_cfg_t *config);

  形参 channel使用的 ADC 通道,它的可选值如下:

typedef enum 
{ADC_CHANNEL_0,     ///< ADC channelADC_CHANNEL_1,     ///< ADC channelADC_CHANNEL_2,     ///< ADC channelADC_CHANNEL_3,     ///< ADC channelADC_CHANNEL_4,     ///< ADC channelADC_CHANNEL_5,     ///< ADC channelADC_CHANNEL_6,     ///< ADC channelADC_CHANNEL_7,     ///< ADC channelADC_CHANNEL_8,     ///< ADC channelADC_CHANNEL_9,     ///< ADC channel
} adc_channel_t;

  形参 configADC 单次转换通道配置的结构体指针,它的定义如下:

typedef struct 
{adc_atten_t atten;              // ADC的衰减系数adc_bitwidth_t bitwidth;        // ADC的转换结果位
} adc_oneshot_chan_cfg_t;

  形参 attenADC 的衰减系数,ESP32 的 ADC 采样电压为 1100mV,只能测量 0 ~ 1100mV 之间的电压,如果要测量更大范围的电压,必须设置衰减系数。

typedef enum 
{ADC_ATTEN_DB_0   = 0,   // 不衰减,可测量范围0~1.2VADC_ATTEN_DB_2_5 = 1,   // 衰减2.5db,可测量范围0~1.5VADC_ATTEN_DB_6   = 2,   // 衰减6db,可测量范围0~2.0VADC_ATTEN_DB_12  = 3,   // 衰减12db,可测量范围0~3.3VADC_ATTEN_DB_11 __attribute__((deprecated)) = ADC_ATTEN_DB_12,  ///<This is deprecated, it behaves the same as `ADC_ATTEN_DB_12`
} adc_atten_t;

  形参 bitwidthADC 的转换结果位,它的可选值如下:

typedef enum 
{ADC_BITWIDTH_DEFAULT = 0, ///< Default ADC output bits, max supported width will be selectedADC_BITWIDTH_9  = 9,      ///< ADC output width is 9BitADC_BITWIDTH_10 = 10,     ///< ADC output width is 10BitADC_BITWIDTH_11 = 11,     ///< ADC output width is 11BitADC_BITWIDTH_12 = 12,     ///< ADC output width is 12BitADC_BITWIDTH_13 = 13,     ///< ADC output width is 13Bit
} adc_bitwidth_t;

2.3、读取单次ADC采样的原始数据

  我们可以使用 adc_oneshot_read() 函数 读取单次 ADC 采样的原始数据,该函数的原型如下:

/*** @brief 读取单次ADC采样的原始数据* * @param handle ADC句柄* @param chan 使用的ADC通道* @param out_raw 转换后的原始数据* @return esp_err_t ESP_OK表示读取成功,其它表示读取失败*/
esp_err_t adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t chan, int *out_raw);

2.4、获得ADC校准结果

  我们可以使用 adc_oneshot_get_calibrated_result() 函数 获得 ADC 校准结果,该函数的原型如下:

/*** @brief 获得ADC校准结果* * @param handle ADC句柄* @param cali_handle ADC校准句柄* @param chan 使用的ADC通道* @param cali_result 校准后的结构* @return esp_err_t */
esp_err_t adc_oneshot_get_calibrated_result(adc_oneshot_unit_handle_t handle, adc_cali_handle_t cali_handle, adc_channel_t chan, int *cali_result);

  形参 cali_handleADC 校准句柄,它的定义如下:

struct adc_cali_scheme_t
{esp_err_t (*raw_to_voltage)(void *arg, int raw, int *voltage);  // 将ADC原始数据转换为校准电压函数指针void *ctx;                                                      // 用户上下文
};typedef struct adc_cali_scheme_t *adc_cali_handle_t;

  这里用户需要实现将 ADC 读取的原始数据转换成校准后电压的函数,它的声明如下:

esp_err_t raw_to_voltage(void *arg, int raw, int *voltage);

三、实验例程

  这里,我们在【components】文件夹下的【peripheral】文件夹下的【inc】文件夹(用来存放头文件)新建一个 bsp_adc.h 文件,在【components】文件夹下的【peripheral】文件夹下的【src】文件夹(用来存放源文件)新建一个 bsp_adc.c 文件。

#ifndef __BSP_ADC_H__
#define __BSP_ADC_H__#include "esp_adc/adc_oneshot.h"extern adc_oneshot_unit_handle_t g_adc_oneshot_unit_handle;void bsp_adc_oneshot_init(adc_oneshot_unit_handle_t *handle, adc_unit_t unit, adc_channel_t channel);
int bsp_adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t adc_channel);#endif // !__BSP_ADC_H__
#include "bsp_adc.h"adc_oneshot_unit_handle_t g_adc_oneshot_unit_handle;/*** @brief ADC单次转换初始化函数* * @param handle ADC句柄* @param unit 使用的ADC单元* @param channel 使用的ADC通道*/
void bsp_adc_oneshot_init(adc_oneshot_unit_handle_t *handle, adc_unit_t unit, adc_channel_t channel)
{adc_oneshot_unit_init_cfg_t adc_oneshot_unit_init_config = {0};adc_oneshot_chan_cfg_t adc_oneshot_channel_config = {0};adc_oneshot_unit_init_config.unit_id = unit;                        // 使用的ADC单元adc_oneshot_unit_init_config.clk_src = ADC_RTC_CLK_SRC_DEFAULT;     // ADC的时钟源adc_oneshot_new_unit(&adc_oneshot_unit_init_config, handle);adc_oneshot_channel_config.atten = ADC_ATTEN_DB_12;                 // 衰减系数adc_oneshot_channel_config.bitwidth = ADC_BITWIDTH_12;              // ADC的位数adc_oneshot_config_channel(*handle, channel, &adc_oneshot_channel_config);
}/*** @brief ADC单次读取原始数据* * @param handle ADC句柄* @param adc_channel 使用的ADC通道* @return int 读取的原始数据*/
int bsp_adc_oneshot_read(adc_oneshot_unit_handle_t handle, adc_channel_t adc_channel)
{int raw_data = 0;esp_err_t result = ESP_OK;result = adc_oneshot_read(handle, adc_channel, &raw_data);return result == ESP_OK ? raw_data : -1;
}

  然后,我们修改【components】文件夹下【peripheral】文件夹下的 CMakeLists.txt 文件。

# 源文件路径
set(src_dirs src)# 头文件路径
set(include_dirs inc)# 设置依赖库
set(requires driveresp_adc
)# 注册组件到构建系统的函数
idf_component_register(# 源文件路径SRC_DIRS ${src_dirs}# 自定义头文件的路径INCLUDE_DIRS ${include_dirs}# 依赖库的路径REQUIRES ${requires}
)# 设置特定组件编译选项的函数
# -ffast-math: 允许编译器进行某些可能减少数学运算精度的优化,以提高性能。
# -O3: 这是一个优化级别选项,指示编译器尽可能地进行高级优化以生成更高效的代码。
# -Wno-error=format: 这将编译器关于格式字符串不匹配的警告从错误降级为警告。
# -Wno-format: 这将完全禁用关于格式字符串的警告。
component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)

  修改【main】文件夹下的 main.c 文件。

#include <stdio.h>#include "freertos/FreeRTOS.h"#include "bsp_adc.h"// app_main()函数是ESP32的入口函数,它是FreRTOS的一个任务,任务优先级是1
// main()函数是C语言入口函数,它会在编译过程中插入到二进制文件中的
void app_main(void)
{bsp_adc_oneshot_init(&g_adc_oneshot_unit_handle, ADC_UNIT_1, ADC_CHANNEL_9);while (1){int raw_data = bsp_adc_oneshot_read(g_adc_oneshot_unit_handle, ADC_CHANNEL_9);int voltage = 3300 * raw_data / 4096;;printf("voltage = %dmV\r\n", voltage);// 将一个任务延迟给定的滴答数,IDF中提供pdMS_TO_TICKS可以将指定的ms转换为对应的tick数vTaskDelay(pdMS_TO_TICKS(1000));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/902259.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【刷题笔记】力扣 40. 组合总和 II——回溯算法中的去重

40. 组合总和 II 中等 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意:解集不能包含重复的组合。 示例 1: 输入: candidates = [10,1,2,7,6,1,…

Spring AI 搭建AI原生应用 [clone]

作者 | 文心智能体平台导读 本文以快速开发一个 AI 原生应用为目的,介绍了 Spring AI 的包括对话模型、提示词模板、Function Calling、结构化输出、图片生成、向量化、向量数据库等全部核心功能,并介绍了检索增强生成的技术。依赖 Spring AI 提供的功能,我们可以轻松开发出…

mybatis逆向工程插件配置(mybatis-generator-maven-plugin)

MyBatis逆向工程是一种自动化工具,可以将数据库表结构转换为MyBatis的Mapper XML文件和相应的Java接口和对应的实体类。 1.生成maven项目 2.pom.xml文件中导入逆向工程插件相关配置<!--mybatis逆向工程--><build><plugins><!--其中的一个插件,逆向工程插…

Day01-Java项目学习

Day01 后端环境搭建 lombok插件 通过lombok插件。@Data 可以使用@Data、@Getter、@Setter等注解的形式,来对一个Java Bean(具有Getter,Setter方法的对象)实现快速的初始化。 @Slf4j 可以以注解的形式,自动化日志变量,通过添加@Slf4j(simple logging Facade for Java)生成…

20241105 实验一 《Python程序设计》

课程:《Python程序设计》 班级: 2411 姓名: 王梓墨 学号:20241105 实验教师:王志强 实验日期:2025年3月12日 必修/选修: 公选课 一.实验内容 1.熟悉Python开发环境; 2.练习Python运行、调试技能;(编写书中的程序,并进行调试分析) 3.编写程序,练习变量和类型、字…

英语四级备考第二天

第二天 今天是开始英语备考的第二天,当迈出第二步的时候,就意味着正走在通过考试的路上。到时当你以425分毋庸置疑地通过考试时,过去的90天都不曾虚度。 单词 今天新学的单词加上昨天应复习的单词,在50~60个之间。阅读 今天的阅读还是用扇贝单词推荐的包含学习的单词的文章…

投资日记_道氏理论技术分析

主要用于我自己参考,我感觉我做事情的时候容易上头,忘掉很多事情。技术分析有很多方法,但是我个人相信并实践的还是以道氏理论为根本的方法。方法千千万万只有适合自己价值观,习惯,情绪,性格的方法才是好的方法。 趋势 趋势是技术分析的根本,要是连当前趋势都看不懂,最…

asp.net core webapi 完整Swagger配置

在当前项目下新建Utility文件夹,Utility文件夹下面在创建SwaggerExt文件夹,文档结果如下 CustomSwaggerExt.cs文件如下using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models;namespace xxxxxxxxxx {/// <summary>/// 扩展Swagger/// </summary>pub…

ciscnccb半决赛

AWDP typo 一道2.31的堆题漏洞点位于edit功能,snprintf函数把用户输入作为format,导致了堆溢出以及格式化字符串漏洞fix 从程序的代码不难看出分配出来的堆,前面八个字节是堆的size,后面的空间才是数据域 这里原意是修改heap的size,但是用错了函数,我们修改最大读入的siz…

AI全天候智能助手,为您构建私人数据库

在数字化转型浪潮中,AI与大数据技术已成为企业提升效率、优化服务的核心引擎。思通数科凭借其自主研发的大数据智能系统,以AI为核心,打造了一站式解决方案,覆盖消费者服务、商家赋能与平台运营三大领域,助力用户与合作伙伴实现智能化升级。以下是该系统的核心功能与价值解…

安装 Prometheus监控主机服务

一、安装 Prometheus 下载 Prometheus 首先,访问 Prometheus 官网 获取最新版本的下载链接,然后使用 wget 下载:wget https://github.com/prometheus/prometheus/releases/download/v3.2.1/prometheus-3.2.1.linux-amd64.tar.gz解压并安装解压下载的文件:tar -xvzf prometh…