ESP32S3基于espidf ADC使用

devtools/2025/2/12 18:01:40/

ESP32S3基于espidf ADC使用


  • 官方在线文档介绍模数转换器:https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32s3/api-reference/peripherals/adc_oneshot.html
  • 🔖espidf版本:v5.4
  • 模数转换器 (ADC)转换方式:
    • 模数转换器 (ADC) 单次转换模式驱动
    • 模数转换器 (ADC) 连续转换模式驱动
    • 模数转换器 (ADC) 带校准驱动
  • ESP32-S3 功能框图
    在这里插入图片描述

ESP32S3 ADC介绍

ESP32-S3 内置了两个 12 位的 SAR ADC,可测量最多来自 20 个管脚的模拟信号。

  • SAR ADC概图
    在这里插入图片描述
主要特性
  • 支持 12 位采样分辨率
    • 支持采集最多 20 个管脚上的模拟电压

  • RTC ADC1/2 控制器:
    – 支持单次转换
    – 支持在低功耗模式下工作,如 Deep-sleep
    – 可由 ULP 协处理器配置

  • DIG ADC1 控制器:
    – 配有多通道扫描控制模块,支持多通道扫描模式
    – 提供模式控制模块,支持单 SAR ADC 采样模式
    – 在多通道扫描模式下,支持自定义扫描通道顺序
    – 提供两个滤波器,滤波系数可配
    – 支持阈值监控,采样值大于设置的高阈值或小于设置的低阈值将产生中断
    – 支持 DMA。

  • SAR ADC 的主要元件与连接情况见图
    在这里插入图片描述
    在这里插入图片描述

  • SAR ADC 模块主要包括以下部分:
    • SAR ADC1:可对 10 个通道进行电压检测;
    • SAR ADC2:可对 10 个通道进行电压检测;

  • SAR ADC 的信号输入
    在这里插入图片描述
    在这里插入图片描述

ADC 转换和衰减

SAR ADC 转换模拟信号时,转换分辨率(12 位)电压范围为 0 mV ~ Vref。其中,Vref 为 SAR ADC 内部参考电
压,出厂设定为 1100 mV。因此,转换结果 (data) 可以使用以下公式转换成模拟电压输出 Vdata:
在这里插入图片描述

  • ADC 经硬件校准和 软件校准后的结果如表下表 所示。如需更高的精度,可选用其他方法自行校准。
    在这里插入图片描述
  • ✨在使用ADC测量模拟输入电压时,被测电压信号,阈值最好不要超过3V。不然精度会比上表所述低。
  • 针对esp32型号,只有在未启动Wi-Fi 驱动程序下,才能使用 ADC2。
    在这里插入图片描述
  • esp32S3 SAR ADC2的数字控制器无法工作

ESP32-S3 SAR ADC2 的数字控制器(即DIGADC2控制器)可能收到错误的采样启动信号,导致控制器进入无法工作的状态。

  • 无变通方法。建议使用RTC控制器来控制SAR ADC2。

🔰编译器不同版本和ADC驱动程序差异

  • 在当前所使用的v5.4版本下,所调用的ADC驱动头文件:
    adc_cali.hadc_cali_scheme.hadc_continuous.hadc_oneshot.h
  • 在旧版本中,所包含的头文件:
#include "driver/adc.h"

当前版本(v5.4)下,部分旧版本的API程序还是可以使用,可能在未来某个版本中会全部移除。有些API已经不支持了,仍继续使用的话,程序运行可能会报错。并且编译时会报警告信息:

#warning "legacy adc driver is deprecated, please migrate to use esp_adc/adc_oneshot.h and esp_adc/adc_continuous.h for oneshot mode and continuous mode drivers respectively"

📘数转换器 (ADC) 单次转换模式驱动


  • 所需包含的头文件:
#include "esp_adc/adc_oneshot.h"
  • ADC 驱动代码
  • 模数转换器 (ADC) 单次转换模式驱动可以参考:v5.4\esp-idf\examples\peripherals\adc\oneshot_read
#include <stdio.h>
#include "esp_adc/adc_oneshot.h"#define ADC1_CHANNEL ADC_CHANNEL_6  // 使用 ADC1 通道 6 (GPIO 6)
#define ADC_ATTEN    ADC_ATTEN_DB_12  // 衰减值
#define ADC_BITWIDTH ADC_BITWIDTH_12  // 位宽void app_main(void) {// 初始化 ADC 单元adc_oneshot_unit_handle_t adc1_handle;adc_oneshot_unit_init_cfg_t init_config = {.unit_id = ADC_UNIT_1,  // 使用 ADC1};ESP_ERROR_CHECK(adc_oneshot_unit_init(&init_config, &adc1_handle));// 配置 ADC 通道adc_oneshot_chan_cfg_t channel_config = {.atten = ADC_ATTEN,  // 衰减值.bitwidth = ADC_BITWIDTH,  // 位宽};ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC1_CHANNEL, &channel_config));// 读取 ADC 值while (1) {int adc_raw_value = 0;ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_CHANNEL, &adc_raw_value));printf("ADC Raw Value: %d\n", adc_raw_value);// 延时 1 秒vTaskDelay(pdMS_TO_TICKS(1000));}// 释放资源(此代码不会执行到此处,仅为示例)ESP_ERROR_CHECK(adc_oneshot_unit_deinit(adc1_handle));
}

在这里插入图片描述

📗模数转换器 (ADC) 校准驱动

#include <stdio.h>
#include "driver/gpio.h"
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_oneshot.h"
//#include "esp_adc/adc_oneshot_unit.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_err.h"#define TAG "ADC_CAL"#define DEFAULT_VREF    1100  // 默认内部参考电压 (mV)
#define NO_OF_SAMPLES   64    // 采样次数
#define ADC1_CHANNEL ADC_CHANNEL_6  // 使用 ADC1 通道 6 (GPIO 6)
#define ADC_ATTEN    ADC_ATTEN_DB_12  // 衰减值
#define ADC_BITWIDTH ADC_BITWIDTH_12  // 位宽void app_main(void) {// 初始化 ADC 单元adc_oneshot_unit_handle_t adc1_handle;adc_oneshot_unit_init_cfg_t init_config = {.unit_id = ADC_UNIT_1,  // 使用 ADC1};ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc1_handle));// 配置 ADC 通道adc_oneshot_chan_cfg_t channel_config = {.atten = ADC_ATTEN,  // 衰减值.bitwidth = ADC_BITWIDTH,  // 位宽};ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC1_CHANNEL, &channel_config));// 初始化校准方案adc_cali_handle_t adc_cali_handle = NULL;adc_cali_curve_fitting_config_t cali_config = {.unit_id = ADC_UNIT_1,.atten = ADC_ATTEN,.bitwidth = ADC_BITWIDTH,};esp_err_t ret = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle);if (ret == ESP_OK) {printf("Calibration scheme created successfully\n");} else {printf("Failed to create calibration scheme\n");return;}while (1) {int adc_raw_value = 0;ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_CHANNEL, &adc_raw_value));printf("ADC Raw Value: %d\n", adc_raw_value);// 将原始值转换为电压int voltage = 0;if (adc_cali_raw_to_voltage(adc_cali_handle, adc_raw_value, &voltage) == ESP_OK) {printf("ADC Raw Value: %d\tVoltage: %dmV\n", adc_raw_value, voltage);} else {printf("Failed to convert raw value to voltage\n");}vTaskDelay(pdMS_TO_TICKS(1000));}// 释放校准方案资源//  ESP_ERROR_CHECK(adc_cali_delete_scheme(adc_cali_handle));// 释放 ADC 单元资源(此代码不会执行到此处,仅为示例)//  ESP_ERROR_CHECK(adc_oneshot_unit_deinit(adc1_handle));
}

在这里插入图片描述

📒模数转换器 (ADC) 连续转换模式驱动

  • 可以参考例程:v5.4\esp-idf\examples\peripherals\adc\continuous_read
  • ✨连续转换模式需要注意,输出数据格式,只能选择类型2:ADC_DIGI_OUTPUT_FORMAT_TYPE2,否则,使用类型1,烧录后会报错:
    在这里插入图片描述
单通道转换模式和连续多通道转换模式共用驱动实现程序
#include <stdio.h>
#include "driver/gpio.h"
#include "esp_adc/adc_continuous.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "esp_adc/adc_cali_scheme.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_err.h"#define TAG "ADC_CAL"#define DEFAULT_VREF    1100  // 默认内部参考电压 (mV)
#define NO_OF_SAMPLES   64    // 采样次数
#define ADC1_CHANNEL ADC_CHANNEL_6  // 使用 ADC1 通道 6 (GPIO 6)
#define ADC_ATTEN    ADC_ATTEN_DB_12  // 衰减值
#define ADC_BITWIDTH ADC_BITWIDTH_12  // 位宽
#define ADC_CONV_MODE ADC_CONV_SINGLE_UNIT_1  // 使用 ADC1 单通道模式
#define DMA_BUFFER_SIZE 8                  // DMA 缓冲区大小
#define SAMPLE_RATE   10000                   // 采样率 (Hz)//#define oneshot    1		//oneshot模式启用
#define continuous 1		//连续转换模式启用void app_main(void) {
#ifdef oneshot// 初始化 ADC 单元adc_oneshot_unit_handle_t adc1_handle;adc_oneshot_unit_init_cfg_t init_config = {.unit_id = ADC_UNIT_1,  // 使用 ADC1};ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc1_handle));// 初始化 ADC 单元adc_oneshot_unit_handle_t adc1_handle;adc_oneshot_unit_init_cfg_t init_config = {.unit_id = ADC_UNIT_1,  // 使用 ADC1};ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc1_handle));// 配置 ADC 通道adc_oneshot_chan_cfg_t channel_config = {.atten = ADC_ATTEN,  // 衰减值.bitwidth = ADC_BITWIDTH,  // 位宽};ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, ADC1_CHANNEL, &channel_config));#elif continuous// 初始化 ADC 连续模式句柄adc_continuous_handle_t adc_handle = NULL;adc_continuous_handle_cfg_t handle_cfg = {.max_store_buf_size = DMA_BUFFER_SIZE,  // DMA 缓冲区大小.conv_frame_size = DMA_BUFFER_SIZE,     // 每帧数据大小};ESP_ERROR_CHECK(adc_continuous_new_handle(&handle_cfg, &adc_handle));// 配置 ADC 通道adc_digi_pattern_config_t adc_pattern_ch[2] = {{.atten = ADC_ATTEN,.channel = ADC_CHANNEL_6,.unit = ADC_UNIT_1,.bit_width = ADC_BITWIDTH,},{.atten = ADC_ATTEN,.channel = ADC_CHANNEL_7,.unit = ADC_UNIT_1,.bit_width = ADC_BITWIDTH,},};// 配置 ADC 连续模式adc_continuous_config_t adc_config = {.pattern_num = 2,  // 使用 2 个通道.adc_pattern = adc_pattern_ch,.sample_freq_hz = SAMPLE_RATE,  // 采样率.conv_mode = ADC_CONV_MODE,     // 转换模式.format = ADC_DIGI_OUTPUT_FORMAT_TYPE2,  // 输出格式};ESP_ERROR_CHECK(adc_continuous_config(adc_handle, &adc_config));// 启动连续采样ESP_ERROR_CHECK(adc_continuous_start(adc_handle));ESP_LOGI(TAG, "ADC continuous mode started");// 读取采样数据uint8_t buffer[DMA_BUFFER_SIZE] = {0};#endifwhile (1) {#ifdef oneshotint adc_raw_value = 0;ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, ADC1_CHANNEL, &adc_raw_value));printf("ADC Raw Value: %d\n", adc_raw_value);// 将原始值转换为电压int voltage = 0;if (adc_cali_raw_to_voltage(adc_cali_handle, adc_raw_value, &voltage) == ESP_OK) {printf("ADC Raw Value: %d\tVoltage: %dmV\n", adc_raw_value, voltage);} else {printf("Failed to convert raw value to voltage\n");}#elif continuous// 读取采样数据uint32_t ret_num = 0;esp_err_t ret = adc_continuous_read(adc_handle, buffer, DMA_BUFFER_SIZE, &ret_num, 0);if (ret == ESP_OK) {ESP_LOGI(TAG, "Read %"PRIu32" bytes of data", ret_num);// 处理采样数据(例如打印或存储)// for (int i = 0; i < ret_num; i += 2) {  // 假设每个采样点占 2 字节//     uint16_t adc_value = (buffer[i + 1] << 8) | buffer[i];//     printf("ADC Value: %d\n", adc_value);// }// 解析 TYPE2 格式的数据for (int i = 0; i < ret_num; i += 2) {  // 每个采样点占 2 字节uint16_t adc_value = (buffer[i + 1] << 8) | buffer[i];uint8_t unit = (adc_value >> 12) & 0x0F;  // 提取单元标识uint16_t raw_data = adc_value & 0x0FFF;   // 提取 12 位原始数据printf("Unit: %d, Raw Data: %d\n", unit, raw_data);}} else {ESP_LOGE(TAG, "Failed to read data: %d", ret);}
#endifvTaskDelay(pdMS_TO_TICKS(1000));}// 单采样释放校准方案资源//  ESP_ERROR_CHECK(adc_cali_delete_scheme(adc_cali_handle));// 释放 ADC 单元资源(此代码不会执行到此处,仅为示例)//  ESP_ERROR_CHECK(adc_oneshot_unit_deinit(adc1_handle));// 连续采样停止采样并释放资源// ESP_ERROR_CHECK(adc_continuous_stop(adc_handle));// ESP_ERROR_CHECK(adc_continuous_deinit(adc_handle));// ESP_LOGI(TAG, "ADC continuous mode stopped");
}
  • 🔖CMakeLists.txt:
idf_component_register(SRCS "main.c"INCLUDE_DIRS "."REQUIRES driver esp_adc)

http://www.ppmy.cn/devtools/158277.html

相关文章

详解Redis中lua脚本和事务

In learning knowledge, one should be good at thinking, thinking, and thinking again. —-Albert Einstein 引言 Lua脚本的原子性和事务的ACID特性想必大家都很熟悉&#xff0c;本篇文章将从性能表现和原理帮助我们快速理解他们 基本概念 1. Redis Lua 脚本 从 2.6 版本…

2526考研资料分享 百度网盘

通过网盘分享的文件&#xff1a;01、2026【考研数学】 链接:https://pan.baidu.com/s/1PwMzp_yCYqjBqa7492mP3w?pwd98wg 提取码:98wg--来自百度网盘超级会员v3的分享 通过网盘分享的文件&#xff1a;01、2026【考研政治】 链接:https://pan.baidu.com/s/1PwMzp_yCYqjBqa7492…

flutter isolate到底是啥

在 Flutter 中&#xff0c;Isolate 是一种实现多线程编程的机制&#xff0c;下面从概念、工作原理、使用场景、使用示例几个方面详细介绍&#xff1a; 概念 在 Dart 语言&#xff08;Flutter 开发使用的编程语言&#xff09;里&#xff0c;每个 Dart 程序至少运行在一个 Isol…

【Pytorch实战教程】让数据飞轮转起来:PyTorch Dataset与Dataloader深度指南

文章目录 让数据飞轮转起来:PyTorch Dataset与Dataloader深度指南一、为什么需要数据管理组件?二、Dataset:数据集的编程接口2.1 自定义Dataset三要素2.2 实战案例:图像分类数据集三、Dataloader:高效数据流水线3.1 核心参数解析3.2 数据流可视化3.3 多卡训练支持四、综合…

【C++高并发服务器WebServer】-17:阻塞/非阻塞和同步/异步、五种IO模型、Web服务器

本文目录 一、阻塞/非阻塞、同步/异步1.1 辨析1.2 异步io接口 二、五种IO模型2.1 阻塞 blocking 模型2.2 非阻塞 NIO 模型2.3 IO多路复用2.4 信号驱动Signal-driven2.5 异步 三、Web Sever 网页服务器3.1 HTTP的请求响应步骤3.2 HTTP请求与响应报文格式3.3 HTTP请求方法3.4 HTT…

element-plus 解决el-dialog背后的页面滚动问题,及其内容有下拉框出现错位问题

这个问题通常是因为 el‑dialog 默认会锁定 body 的滚动&#xff08;通过给 body 添加隐藏滚动条的样式&#xff09;&#xff0c;从而导致页面在打开对话框时跳转到顶部。解决方法是在使用 el‑dialog 时禁用锁定滚动功能。 <el-dialogv-model"dialogVisible":lo…

数据结构 单链表的模拟实现

一、链表的定义 线性表的链式存储就是链表。 它是将元素存储在物理上任意的存储单元中&#xff0c;由于⽆法像顺序表⼀样通过下标保证数据元素之间的逻辑关系&#xff0c;链式存储除了要保存数据元素外&#xff0c;还需额外维护数据元素之间的逻辑关系&#xff0c;这两部分信息…

VideoWorld技术在智能货柜商品识别与数量统计的总结

&#x1f31f; “VideoWorld” 模型仅凭视觉信息即可实现知识学习&#xff0c;不依赖语言模型。 &#x1f916; 模型在围棋和机器人模拟任务中展现出卓越的推理和规划能力。 一、技术实现核心 生成式数据增强 功能&#xff1a;通过VideoWorld生成多样化的合成数据&#xff08;…