ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ESP-IDF ADC 单次模式(Oneshot Mode)驱动:从资源分配到原始数据读取的完整实战指南

ESP-IDF ADC 单次模式(Oneshot Mode)驱动:从资源分配到原始数据读取的完整实战指南 ESP-IDF ADC 单次模式Oneshot Mode驱动从资源分配到原始数据读取的完整实战指南【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf导读本文围绕 ESP-IDF 的 ADC Oneshot 模式驱动位于components/esp_adc系统讲解如何从单个模拟输入通道按需执行一次 ADC 转换。无论你是要周期性采样电池电压、读取电位器位置还是做低频传感器检测单次模式都是开销最小、最直接的选择。读完本文你将掌握 ADC 单元句柄的创建与回收、通道衰减与位宽配置、原始转换结果读取与电压换算公式、硬件限制规避、电源管理适配、IRAM 安全以及线程安全保证等全部关键要点并能直接跑通 oneshot_read 官方示例。单次模式是什么Oneshot 模式单次模式允许你在选定的模拟输入通道上执行按需、单次的 ADC 转换。它非常适合采样频率较低、由事件或任务触发的采样场景与之相对的连续数据采集DMA 流式读取则由 ADC Continuous 模式驱动承担见 ADC Continuous 模式驱动。从驱动视角看一个 ADC 实例由adc_oneshot_unit_handle_t句柄表示其类型定义见 adc_oneshot.h。整个使用流程可分为四个阶段资源分配创建 ADC 单元句柄使用完毕后回收资源单元配置配置 ADC 通道的衰减与位宽读取转换结果获取 ADC 原始转换结果异常与约束处理硬件限制、电源管理、IRAM 安全、线程安全与 Kconfig 选项。资源分配创建与回收 ADC 单元句柄ADC Oneshot 驱动基于芯片的 SAR ADC 模块实现。不同 ESP 芯片拥有不同数量的独立 ADC可用 ADC 数量由SOC_ADC_PERIPH_NUM宏记录例如 ESP32/ESP32-S3 等芯片拥有 ADC1 和 ADC2 两个单元。安装 ADC 实例时需要先填充初始化配置结构体adc_oneshot_unit_init_cfg_t该结构体定义在 adc_oneshot.h包含三个成员unit_id选择使用哪个 ADC 单元ADC_UNIT_1或ADC_UNIT_2枚举定义见 adc_types.h。具体哪些 GPIO 可作模拟输入请查阅芯片数据手册的 ADC IO 说明clk_src选择 ADC 的时钟源。若设为 0驱动会回退到默认时钟源见adc_oneshot_clk_src_tulp_mode设置 ADC 是否工作于 ULP 模式。普通应用填ADC_ULP_MODE_DISABLE即可枚举见 adc_types.h。配置完成后调用adc_oneshot_new_unit创建 ADC 单元句柄。从源码实现看adc_oneshot.c该函数会依次执行参数校验、内存分配内存分配策略受CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM影响见下文 IRAM Safe 小节、单元占用标记基于原子操作atomic_compare_exchange_strong见 adc_oneshot.c、时钟源频率获取与 HAL 层初始化。可能的失败原因包括ESP_ERR_INVALID_ARG参数无效如空指针、非法的unit_idESP_ERR_NO_MEM内存不足ESP_ERR_NOT_FOUND目标 ADC 单元已被其他驱动/外设注册占用ESP_FAIL时钟源初始化不正确。注意在 ESP32-C3 上除非开启CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3否则驱动会在adc_oneshot_new_unit阶段直接拒绝 ADC2见 adc_oneshot.c。当 ADC 实例不再使用时调用adc_oneshot_del_unit回收句柄相关的硬件与软件资源会被一并释放。代码示例创建 ADC 单元句柄adc_oneshot_unit_handle_t adc1_handle; adc_oneshot_unit_init_cfg_t init_config1 { .unit_id ADC_UNIT_1, .ulp_mode ADC_ULP_MODE_DISABLE, }; ESP_ERROR_CHECK(adc_oneshot_new_unit(init_config1, adc1_handle));代码示例回收 ADC 单元ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle));单元配置设置通道衰减与位宽创建 ADC 实例后需要配置 ADC 通道以测量模拟信号。通道配置结构体adc_oneshot_chan_cfg_t定义见 adc_oneshot.h包含两个关键成员attenADC 衰减系数adc_atten_t。衰减越大可测量的输入电压范围越大但分辨率相应降低。可选值与含义见 adc_types.hADC_ATTEN_DB_0无输入衰减可测量约 0950 mVADC_ATTEN_DB_2_5输入衰减约 2.5 dB扩展量程至约 01250 mVADC_ATTEN_DB_6输入衰减约 6 dB扩展量程至约 01750 mVADC_ATTEN_DB_12输入衰减约 12 dB扩展量程至约 03100 mV。各衰减档位的精确量程取决于具体芯片与校准数据请以数据手册中ADC Characteristics章节为准bitwidth原始转换结果的位宽adc_bitwidth_t见 adc_types.h。可选ADC_BITWIDTH_9~ADC_BITWIDTH_13或使用ADC_BITWIDTH_DEFAULT0让驱动自动选择芯片支持的最大位宽。调用adc_oneshot_config_channel使配置生效该函数可被多次调用来配置不同的 ADC 通道驱动会在内部保存每一路通道的配置。从实现看adc_oneshot.c该函数会校验衰减与位宽合法性位宽必须落在ADC_LL_RTC_MIN_BITWIDTH与ADC_LL_RTC_MAX_BITWIDTH之间或等于ADC_BITWIDTH_DEFAULT将对应 GPIO 初始化为模拟功能gpio_config_as_analog见 adc_oneshot.c并在临界区rtc_spinlock内完成 HAL 层通道配置。提示想知道某个 GPIO 对应哪个 ADC 通道或某个 ADC 通道对应哪个 GPIO可使用adc_oneshot_io_to_channel与adc_oneshot_channel_to_io两个辅助函数声明见 adc_oneshot.h。代码示例配置两个 ADC 通道adc_oneshot_chan_cfg_t config { .bitwidth ADC_BITWIDTH_DEFAULT, .atten ADC_ATTEN_DB_12, }; ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN0, config)); ESP_ERROR_CHECK(adc_oneshot_config_channel(adc1_handle, EXAMPLE_ADC1_CHAN1, config));读取转换结果获取 ADC 原始数据完成上述配置后ADC 即可开始测量配置通道上的模拟信号。调用adc_oneshot_read即可获取某一通道的原始转换结果。adc_oneshot_read的底层流程见 adc_oneshot.c可以概括为校验句柄、输出指针与通道号合法性通过adc_lock_try_acquire尝试获取 ADC 共享硬件锁——这是多驱动共享 ADC 硬件时的互斥保护在临界区中使能模拟时钟ANALOG_CLOCK_ENABLE调用 HAL 层adc_oneshot_hal_setup配置通道在支持硬件校准的芯片上SOC_ADC_CALIBRATION_V1_SUPPORTED完成校准码设置执行转换adc_oneshot_hal_convert随后释放时钟与锁。需要注意的行为特性线程安全该函数使用互斥锁mutex避免并发硬件访问冲突因此不能在 ISR 上下文中调用若确实需要在中断里读取可考虑 ISR 变体adc_oneshot_read_isr见 adc_oneshot.c超时返回当 ADC 正被其他驱动/外设如连续模式驱动、Wi-Fi 等占用时adc_oneshot_read会返回ESP_ERR_TIMEOUT此时读取到的原始结果是无效的参数错误句柄或输出指针为空、通道号非法时返回ESP_ERR_INVALID_ARG。原始结果换算电压的公式adc_oneshot_read返回的是原始数字量。要将原始值换算为电压可使用如下公式Vout Dout * Vmax / Dmax (1)符号含义Vout数字输出结果代表电压值DoutADC 原始数字读取结果Vmax最大可测量输入模拟电压与 ADC 衰减有关参见技术参考手册 On-Chip Sensor and Analog Signal Processing 章节Dmax输出原始数字读取结果的最大值即 2^bitwidth其中 bitwidth 为前面配置的adc_oneshot_chan_cfg_t::bitwidth需要说明的是公式 (1) 是理想化的线性换算。实际芯片的 ADC 存在增益误差、偏移误差与非线性若需要将原始结果精确换算为 mV强烈建议使用 ADC 校准驱动adc_calibration。驱动还提供了adc_oneshot_get_calibrated_result便捷函数一次性完成单次读取 校准换算内部实现为依次调用adc_oneshot_read与adc_cali_raw_to_voltage见 adc_oneshot.c。代码示例读取原始结果ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN0, adc_raw[0][0])); ESP_LOGI(TAG, ADC%d Channel[%d] Raw Data: %d, ADC_UNIT_1 1, EXAMPLE_ADC1_CHAN0, adc_raw[0][0]); ESP_ERROR_CHECK(adc_oneshot_read(adc1_handle, EXAMPLE_ADC1_CHAN1, adc_raw[0][1])); ESP_LOGI(TAG, ADC%d Channel[%d] Raw Data: %d, ADC_UNIT_1 1, EXAMPLE_ADC1_CHAN1, adc_raw[0][1]);硬件限制必须知晓的芯片级约束ADC 外设与其他模块存在共享关系以下是使用 Oneshot 模式时需要注意的硬件限制RNG 与 ADC 共享随机数生成器RNG以 ADC 作为输入源之一。当adc_oneshot_read工作时RNG 产生的随机数随机性会下降该限制适用于非 esp32s31 的芯片单模式限制一个 ADC 单元在任意时刻只能工作于一种操作模式——连续模式或单次模式。adc_oneshot_read已内置了模式互斥保护适用于支持 DMA 连续模式的芯片差分通道极性反转在单端模式下若使用 N 侧通道作为输入接口其原始数据极性会反转。例如输入范围为 -2 V 到 2 V 时N 侧原始码值范围是 4393 到 0。此时请使用 ADC 校准 API 进行换算适用于支持差分输入的芯片SOC_ADC_DIFF_SUPPORTEDADC2 与 Wi-Fi 冲突在 ESP32、ESP32-S2、ESP32-S3 上ADC2 同时被 Wi-Fi 使用。adc_oneshot_read已提供 Wi-Fi 驱动与 ADC Oneshot 驱动之间的互斥保护ESP32-C3 的 ADC2 限制由于硬件限制ESP32-C3 的 ADC2 单次模式不再受支持其结果不稳定详见 ESP32-C3 系列芯片勘误表。出于兼容性考虑可通过使能CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3强制使用 ADC2开发板引脚占用在 ESP32 上部分引脚因开发板设计原因不能用于单次模式例如 ESP32-DevKitC 的 GPIO0 被用于自动下载auto-flashESP-WROVER-KIT 的 GPIO 0、2、4、15 因外部连接用途不同而不可用。电源管理时钟频率稳定性保证当使能电源管理即CONFIG_PM_ENABLE时系统在空闲状态下可能调整 CPU 时钟频率。不过ADC Oneshot 驱动以轮询方式工作adc_oneshot_read会持续占用 CPU 直到函数返回期间其所在任务不会被阻塞。因此在读取期间时钟频率是稳定的不会因动态调频而影响采样精度。从源码角度印证adc_oneshot_read全程在rtc_spinlock临界区与adc_lock互斥保护下同步执行见 adc_oneshot.c不存在让出 CPU 的阻塞点这正是轮询保证时钟稳定这一特性的实现基础。另外驱动在创建/删除单元时还会针对CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP等配置调整睡眠电源域esp_sleep_pd_config以保证轻睡眠场景下 ADC 供电正常见 adc_oneshot.c。IRAM 安全Cache 关闭场景下的使用要点默认情况下所有 ADC Oneshot 驱动 API都不应在 Cache 关闭时运行。Cache 可能因 Flash 写入/擦除、OTA 升级等原因被临时禁用。若在这些场景下调用上述 API可能会看到Illegal Instruction或Load/Store Prohibited等错误。如果确实需要在 Cache 关闭期间读取 ADC 原始结果需要通过 Kconfig 选项CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM将 ADC 快速读取函数放入 IRAM详见下文 Kconfig 小节此时驱动内部会以MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT的内存能力申请内存确保相关数据结构位于内部 RAM见 adc_oneshot.c。线程安全无需额外加锁的 API以下 API 被保证是线程安全的见 adc_oneshot.h 中的声明注释可以从不同 RTOS 任务中直接调用无需额外加锁保护adc_oneshot_new_unitadc_oneshot_config_channeladc_oneshot_readadc_oneshot_del_unit这种线程安全性在实现上由两部分构成单元占用标记使用 C11 原子操作atomic_compare_exchange_strong见 adc_oneshot.c上下文数据单元句柄数组、APB 外设引用计数的读写则通过_lock_t mutex见 adc_oneshot.c保护。Kconfig 选项按需调整驱动行为ADC Oneshot 驱动相关的 Kconfig 选项定义在 components/esp_adc/Kconfig 中核心选项如下CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM默认关闭控制 ADC 快速读取函数放在 IRAM 还是 Flash。需要 IRAM 安全Cache 关闭时读取时开启详见上文 IRAM Safe 小节CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3默认关闭仅 ESP32-C3ESP32-C3 上 ADC2 数字控制器不稳定因此默认不建议使用 ADC2 单次模式如确需使用可开启此项强制启用CONFIG_ADC_DISABLE_DAC_OUTPUT默认开启需 SOC 支持 DAC当 ADC2 被使用时驱动会禁用对应 DAC 通道输出ESP32 上为 IO25/IO26ESP32-S2 上为 IO17/IO18。关闭此项可用于测试场景——用内部 ADC 测量 DAC 输出CONFIG_ADC_ENABLE_DEBUG_LOG默认关闭使能 ADC 驱动的调试日志仅影响 ADC 驱动本身不影响其他驱动。官方示例与测试验证仓库在 examples/peripherals/adc/oneshot_read 提供了完整可运行的官方示例它演示了如何使用 Oneshot 驱动从 GPIO 引脚获取一次 ADC 读数如何结合 ADC Calibration 函数获得以 mV 为单位的校准结果。示例在app_main中依次完成 ADC1 初始化、通道配置、校准初始化然后在while(1)循环中每秒读取两个通道的原始数据并打印校准电压完整代码见 oneshot_read_main.c。编译烧录命令idf.py -p PORT flash monitor退出串口监视器按Ctrl-]。运行后串口输出类似摘自 README.mdI (304) ADC_ONESHOT: calibration scheme version is Curve Fitting I (314) ADC_ONESHOT: ADC1 Channel[2] Raw Data: 0 I (314) ADC_ONESHOT: ADC1 Channel[2] Cali Voltage: 0 mV I (1324) ADC_ONESHOT: ADC1 Channel[3] Raw Data: 664 I (1324) ADC_ONESHOT: ADC1 Channel[3] Cali Voltage: 559 mV注意示例代码中有两处值得借鉴的细节在 ESP32 上示例默认使用ADC_CHANNEL_4/5其他芯片使用ADC_CHANNEL_2/3见 oneshot_read_main.c这体现了不同芯片 ADC IO 映射不同的事实校准初始化会依次尝试 Curve Fitting 与 Line Fitting 两种校准方案若 eFuse 未烧录校准数据会打印eFuse not burnt, skip calibration警告并跳过校准见 oneshot_read_main.c。仓库同时提供了针对该示例的 pytest 测试脚本 pytest_adc_oneshot.py 及多芯片 CI 配置sdkconfig.ci可用于验证驱动在真实硬件上的行为。小结ADC Oneshot 模式驱动以创建句柄 → 配置通道 → 按需读取 → 回收句柄四个步骤覆盖了低频、按需采样的全部需求。本文从 官方文档 出发结合 驱动头文件 与 驱动实现 的源码级细节阐明了参数含义、底层调用链、硬件限制与工程注意事项。实际项目中若需要精确电压值请务必配合 ADC 校准驱动 使用而非直接对原始值做线性换算。【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表