ADC Continuous Read 示例

[English]

示例说明

本示例展示如何初始化和配置 ADC 以及如何使用 ADC 连续采样模式采集模拟输入信号并进行处理。有关 ADC 连续转换模式的说明可参考 模数转换器 (ADC) 连续转换模式驱动。学习该示例前,建议先掌握 FreeRTOS 信号量的相关内容,其基础说明及 API 使用示例可参考 信号量和互斥锁 文档。

运行方法

示例完整代码见 ADC Continuous Read 示例。运行前的配置说明、构建与烧录流程详见 adc 目录下的 README.md 文件。

如需自定义配置项及查看默认值,可参考 全局变量/宏定义说明 部分。

头文件说明

本示例所使用的头文件涵盖了 FreeRTOS 任务管理与同步机制、常用系统工具以及 ADC 连续采样驱动等基础模块。为任务创建、ADC 初始化、采集及处理提供支持。

各头文件按功能分类如下:

  1. FreeRTOS 任务调度 :提供任务创建、调度和管理功能,并支持任务同步机制,确保多任务环境下的资源共享和通信。

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
  1. 系统工具 :提供系统配置文件,以及输入输出、字符串处理、日志记录功能,用于程序的调试、配置和运行管理。

#include <string.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "esp_log.h"
  1. ADC 驱动 :提供 ADC 连续采样模式初始化、通道配置、原始数据读取及采集结果处理功能。

#include "esp_adc/adc_continuous.h"

全局变量/宏定义说明

本示例中涉及的宏定义主要用于定义 GPIO 输入输出引脚以及中断标志位。

宏定义按功能分类如下:

  1. ADC 单元选择

  • 定义所使用的 ADC 单元。本示例使用 ADC_UNIT_1,即 ADC1 外设。

#define EXAMPLE_ADC_UNIT                    ADC_UNIT_1
  • 将 ADC 单元宏转换为字符串形式,用于日志或调试输出。

#define _EXAMPLE_ADC_UNIT_STR(unit)         #unit
#define EXAMPLE_ADC_UNIT_STR(unit)          _EXAMPLE_ADC_UNIT_STR(unit)
  1. ADC 参数设置

  • 设置 ADC 转换模式,指定使用单 ADC 单元采样。

#define EXAMPLE_ADC_CONV_MODE               ADC_CONV_SINGLE_UNIT_1
  • 设置 ADC 通道的衰减为 0 dB。

#define EXAMPLE_ADC_ATTEN                   ADC_ATTEN_DB_0
  • 设置 ADC 采样位宽,通常使用芯片支持的最大位宽 SOC_ADC_DIGI_MAX_BITWIDTH

#define EXAMPLE_ADC_BIT_WIDTH               SOC_ADC_DIGI_MAX_BITWIDTH
  1. ADC 输出数据格式与访问:根据芯片型号(是否是 ESP32 芯片或 ESP32-S2 芯片)选择不同的数据输出格式与访问路径。

  • 定义 ADC 数字输出数据格式,针对不同芯片选择 TYPE1TYPE2

  • 根据芯片类型定义如何从 ADC 输出数据结构中获取通道号。

  • 根据芯片类型定义如何从 ADC 输出数据结构中获取原始采样数据。

#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#define EXAMPLE_ADC_OUTPUT_TYPE             ADC_DIGI_OUTPUT_FORMAT_TYPE1    // 输出数据格式
#define EXAMPLE_ADC_GET_CHANNEL(p_data)     ((p_data)->type1.channel)       // 获取通道号
#define EXAMPLE_ADC_GET_DATA(p_data)        ((p_data)->type1.data)          // 获取原始采样数据
#else
#define EXAMPLE_ADC_OUTPUT_TYPE             ADC_DIGI_OUTPUT_FORMAT_TYPE2    // 输出数据格式
#define EXAMPLE_ADC_GET_CHANNEL(p_data)     ((p_data)->type2.channel)       // 获取通道号
#define EXAMPLE_ADC_GET_DATA(p_data)        ((p_data)->type2.data)          // 获取原始采样数据
#endif
  1. 数据采集长度:定义每次数据采集的读取长度为 256,用于分配缓冲区的大小。

#define EXAMPLE_READ_LEN                    256
  1. 定义全局变量:

  • 根据芯片型号定义 ADC 通道数组 channel[]

    • 当目标芯片为 ESP32 时,选择 ADC_CHANNEL_6ADC_CHANNEL_7

    • 当目标芯片为其他芯片时,选择 ADC_CHANNEL_2ADC_CHANNEL_3

  • 定义 FreeRTOS 任务句柄变量 s_task_handle,用于在 FreeRTOS 环境下管理或控制任务。

任务函数说明

本示例中,为了实现 ADC 连续采样模式的初始化,并成功完成采样及数据处理,提供了两个相关任务函数:ADC 初始化函数和连续采样完成回调函数。

ADC 初始化函数

continuous_adc_init() 为 ADC 初始化函数,用于初始化 ADC 连续采样模式并完成通道配置,使得后续的数据采集和处理能够顺利进行。

参数解释

传入参数

参数功能

参数说明

channel

指向 ADC 通道数组的指针

用于指定需要进行连续采样的通道列表。每个元素表示一个 ADC 通道编号。

channel_num

通道数组中通道的数量

用于配置 ADC 连续采样时实际使用的通道数。

out_handle

ADC 模块句柄

输出参数,返回初始化完成的 ADC 连续采样模块句柄,用于后续启动采样、读取数据或注销模块时进行操作。

该函数的执行逻辑为:

  1. 初始化 ADC 采样模块

  2. 配置/应用采样参数

  • ADC 通道模式数组长度为 SOC_ADC_PATT_LEN_MAX,为 ADC 数字控制器模式下支持的最大通道配置数量。

  • 遍历配置每个通道并打印配置日志,便于调试和验证。

  1. 将函数内生成的 ADC 采样模块句柄保存到传参 out_handle

连续采样完成回调函数

s_conv_done_cb() 是一个回调函数,主要用于处理 ADC 连续采样模式下的采样完成事件。它在每次 ADC 连续采样完成预定数量的转换后被触发。

参数解释

传入参数

参数功能

参数说明

handle

已创建的 ADC 连续采样模块的句柄

用于访问与当前 ADC 连续采样相关的配置和状态,便于进行进一步操作或管理采样任务。

edata

指向 ADC 连续采样事件的数据结构

用于访问采样数据,从而进行数据处理或其他相关操作。

user_data

用户自定义的数据

用于标识任务句柄或进行任务通知。

该函数的执行逻辑为:

  1. 定义标志变量 mustYield,用于指示在回调执行后是否需要立即切换任务,初始化为 pdFALSE

  2. 调用 vTaskNotifyGiveFromISR() 向指定任务发送通知,告知 ADC 连续采样已完成规定数量的转换。

  3. 判断 mustYield 是否为 pdTRUE,并将其返回给调度器,以便在必要时切换到高优先级任务执行。

主函数说明

本函数展示了 ADC 连续采样模式的完整流程,包括初始化 ADC 单元、配置采样通道、注册采样完成回调、执行软件校准,以及循环读取和处理采样数据。

  1. 定义变量:

  • 创建返回值变量 ret 用于错误检查和日志输出,确保调用者能根据不同返回值采取不同处理。

  • 创建变量 ret_num 并初始化为 0,用于记录每次读取到的数据长度(字节数)。

  • 创建数组 result[] 并初始化为 0xcc,用于存储 ADC 连续采样返回的原始数据。数组长度为自定义宏 EXAMPLE_READ_LEN

  1. 调用 xTaskGetCurrentTaskHandle() 获取当前任务句柄,供回调函数中通知任务使用。进一步说明及使用示例可参考 任务信息 API

  2. 初始化 ADC 连续采样模块:

  • 创建 ADC 连续采样模块句柄 handle 并初始化为 NULL,用于后续操作 ADC 模块。

  • 调用 continuous_adc_init(),根据指定的 ADC 通道数组创建并配置 ADC 连续采样模块,并保存返回的句柄至 handle

  1. 注册事件回调

备注

事件回调函数常用于处理采样结果并进行后续操作,但不是 ADC 联系采样模块中的必备步骤。

  • 如果选择使用回调函数,可以在每次采样完成后由回调函数自动处理数据,适合需要实时处理或数据处理频繁的场景。回调函数可以有效避免轮询等待,提高系统响应效率。

  • 如果不使用回调函数,可以选择通过轮询的方式检测采样是否完成,然后手动处理采样数据。这种方式可能适用于不需要立即处理数据或控制逻辑较简单的场景。

  1. 启动 ADC 连续采样

备注

步骤 6、7 在数据处理循环中执行。

  1. 调用 ulTaskNotifyTake() 阻塞等待回调通知,确保在采样完成后处理数据。

  2. 循环读取数据:

  • 循环调用 adc_continuous_read() 读取 ADC 缓冲区数据,直到缓冲区中没有可用数据(返回 ESP_ERR_TIMEOUT)。进一步介绍及参数说明可参考 ADC 驱动

  • 将读取到的原始数据解析为 adc_digi_output_data_t 结构体,并通过宏 EXAMPLE_ADC_GET_CHANNELEXAMPLE_ADC_GET_DATA 获取通道号和采样值。具体结构体成员可参考 ADC 驱动

  • 检查每条数据的有效性,确保通道号未超出最大通道数,并通过日志打印通道号和采样值。

  • 为防止任务看门狗超时,在每次循环末尾调用 vTaskDelay(1) 暂停 1 个 tick。

  1. 任务结束后停止与释放 ADC 模块。

  • 调用 adc_continuous_stop() 停止连续采样。进一步介绍及参数说明可参考 ADC 驱动

  • 调用 adc_continuous_deinit() 释放 ADC 模块资源。进一步介绍及参数说明可参考 ADC 驱动

备注

在实际应用中,连续采样任务通常为长期运行或常驻任务,因此该步骤一般不被执行,但可以用于防止潜在的程序异常或内存泄漏。