ESP-IDF 模数转换器(ADC)驱动完全指南:oneshot、continuous 与校准原理详解
【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf
导读
本文以 ESP-IDF 官方 ADC 编程指南(docs/en/api-reference/peripherals/adc/index.rst)为主线,系统讲解 Espressif SoC 上 ADC(模数转换器)的核心概念——转换原理、原始数据分辨率、参考电压与衰减,并深入剖析其两大驱动模式:oneshot 模式(单次按需采样)与continuous 模式(DMA 高速连续采样),以及用于提升精度的ADC 校准驱动。阅读完本文,你将掌握 ADC 通道的配置方法、原始读数与电压的换算公式、两种模式各自的资源管理与读取流程,并能通过 Kconfig 选项与 IRAM-safe、电源管理等机制在实际项目中正确选型与调优。
一、ADC 核心概念:从模拟电压到数字量
ADC(Analog to Digital Converter)负责将输入模拟电压转换为数字值。ESP-IDF 的 ADC 驱动 API 返回的均是原始数据(raw data),它以数字形式表征模拟输入信号。
1.1 分辨率与原始数据位宽
默认情况下,ADC 原始结果的位宽为12 位,这意味着输入电压范围被划分为 2¹² =4096 个离散电平,由此决定了可检测的最小输入信号变化量。
原始 ADC 结果data对应的电压Vdata计算公式为:
Vdata = data / (2^bitwidth − 1) × Vref其中:
data:ADC 原始结果;bitwidth:ADC 结果分辨率(如 12 位);Vref:ADC 参考电压。
1.2 参考电压 Vref 的制造偏差
按设计,Vref为1100 mV。但由于芯片制造工艺差异,不同芯片的实际参考电压可能落在1000 mV ~ 1200 mV之间。这一偏差正是需要 ADC 校准驱动的原因——要获得经过校准的精确电压值,请使用 adc_calibration.rst 中介绍的校准驱动,依据芯片实际的Vref对原始结果进行修正。
从源码角度,adc_cali_handle_t校准句柄与adc_cali_raw_to_voltage()等接口定义在 components/esp_adc/include/esp_adc/adc_cali.h,校准方案接口表adc_cali_scheme_t位于 components/esp_adc/interface/adc_cali_interface.h,其实现分布在 components/esp_adc/adc_cali.c、components/esp_adc/adc_cali_curve_fitting.c 等文件中。
1.3 衰减(Attenuation):扩大测量范围
ADC 只能直接测量0 V ~ Vref范围内的模拟电压。要测量更高电压,可在信号进入 ADC 之前先进行衰减。支持的衰减档位如下表:
| 衰减档位 | 比例系数 k(约) |
|---|---|
| 0 dB | k ≈ 100% |
| 2.5 dB | k ≈ 75% |
| 6 dB | k ≈ 50% |
| 12 dB | k ≈ 25% |
衰减档位越高,ADC 能测量的输入电压上限越高。施加衰减后的电压计算公式为:
Vdata = (Vref / k) × (data / (2^bitwidth − 1))其中k是对应衰减档位的比例值,其余变量含义同前。每个衰减档位对应的具体输入电压范围,请查阅目标芯片数据手册(datasheet)中的 "Electrical Characteristics > ADC Characteristics"(ESP32 则为 "Function Description > Analog Peripherals > Analog-to-Digital Converter (ADC)")章节。
二、ADC 驱动模式总览
ESP-IDF 的 ADC 驱动按使用场景分为两种工作模式:
- oneshot 模式:适用于单次、按需采样,一次只对一个通道采样,实现简单、资源占用低;
- continuous 模式:适用于需要周期性或高频连续采集的场景,ADC 自动对一组通道依次采样或对单个通道连续采样,并通过 DMA 将结果高效搬运到内存。
其中 continuous 模式需要芯片支持 DMA(即SOC_ADC_DMA_SUPPORTED)。同一 ADC 单元在同一时刻只能工作于一种模式下,驱动内部已提供互斥保护(详见各模式的硬件限制章节)。
两种模式对应的官方实现分别是 components/esp_adc/adc_oneshot.c 与 components/esp_adc/adc_continuous.c,头文件分别为 components/esp_adc/include/esp_adc/adc_oneshot.h 与 components/esp_adc/include/esp_adc/adc_continuous.h。
三、ADC Oneshot 模式驱动详解
oneshot 模式适合采样频率低、按需触发的应用,例如读取电位器电压、电池电量检测等低频测量任务。
3.1 资源分配:创建与回收 ADC 单元
在 oneshot 驱动视角下,一个 ADC 实例由句柄adc_oneshot_unit_handle_t表示。安装 ADC 实例前需设置初始化配置结构体adc_oneshot_unit_init_cfg_t(定义于 adc_oneshot.h):
unit_id:选择 ADC 单元(ADC_UNIT_1 / ADC_UNIT_2),对应芯片上具体的模拟 IO,可查数据手册或使用adc_oneshot_io_to_channel()反查;clk_src:ADC 时钟源,置 0 时驱动回退到默认时钟源(见adc_oneshot_clk_src_t);ulp_mode:是否在 ULP 模式下使用 ADC。
配置完成后调用adc_oneshot_new_unit()创建单元,成功则返回 ADC 单元句柄。该函数可能因参数非法、内存不足等失败;特别地,当目标 ADC 实例已被占用时会返回ESP_ERR_NOT_FOUND,可用SOC_ADC_PERIPH_NUM宏获知芯片可用 ADC 数量。不再使用时调用adc_oneshot_del_unit()回收实例及其软硬件资源。
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)); // ... 使用完毕后回收 ESP_ERROR_CHECK(adc_oneshot_del_unit(adc1_handle));3.2 通道配置:设置衰减与位宽
创建实例后,通过adc_oneshot_chan_cfg_t(见 adc_oneshot.h)配置要测量的 IO:
atten:ADC 衰减档位,取值范围为上文提到的 0 / 2.5 / 6 / 12 dB;bitwidth:原始转换结果位宽。
调用adc_oneshot_config_channel()使配置生效,该函数可多次调用以配置不同通道,驱动会在内部保存每个通道的配置。
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));3.3 读取转换结果
调用adc_oneshot_read()获取指定通道的原始转换结果:
int adc_raw[2][2]; 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]);该函数使用互斥锁避免并发访问硬件,因此不可以在 ISR 上下文调用;当 ADC 正被其他驱动/外设占用时可能返回ESP_ERR_TIMEOUT,此时读到的原始结果无效。
原始结果换算电压的公式:
Vout = Dout × Vmax / Dmax| 符号 | 含义 |
|---|---|
| Vout | 数字输出结果,代表电压 |
| Dout | ADC 原始数字读数 |
| Vmax | 最大可测输入模拟电压,与 ADC 衰减相关(参考 TRM "On-Chip Sensor and Analog Signal Processing" 章节) |
| Dmax | ADC 原始数字读数最大值,即 2^bitwidth,其中 bitwidth 为配置的通道位宽 |
若要获得以 mV 为单位的精确电压,推荐使用校准驱动(见本文第五章),或直接使用便捷函数adc_oneshot_get_calibrated_result()——它一步完成"读取原始结果 + 校准为电压",该函数同样声明于 adc_oneshot.h。
3.4 oneshot 模式的其他要点
- 电源管理:启用
CONFIG_PM_ENABLE后,系统空闲时系统时钟频率可能被调整。oneshot 驱动以轮询方式工作,adc_oneshot_read()会持续占用 CPU 直到返回,期间任务不会阻塞,因此读取时时钟频率保持稳定。 - IRAM Safe:默认情况下所有 oneshot API 不允许在 Cache 禁用时运行(如 Flash 写入/擦除、OTA 期间),否则可能出现
Illegal Instruction或Load/Store Prohibited错误。 - 线程安全:
adc_oneshot_new_unit、adc_oneshot_config_channel、adc_oneshot_read、adc_oneshot_del_unit均保证线程安全,可在不同 RTOS 任务中直接调用,无需额外加锁。 - Kconfig 选项:
CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM控制 ADC 快速读取函数放置在 IRAM 还是 Flash(见 components/esp_adc/Kconfig)。
四、ADC Continuous 模式驱动详解
continuous 模式下,ADC 对一路或多路模拟输入通道执行自动高速采样,结果通过 DMA 高效传输到内存,适用于音频采集、波形监测、电力计量等高频/周期性数据采集场景。
4.1 转换帧(Conversion Frame)与转换结果
continuous 模式以转换帧为单位组织数据:
- 转换帧(Conversion Frame):一个帧包含多个转换结果,帧大小由
adc_continuous_new_handle()按字节配置; - 转换结果(Conversion Result):一个结果由多个字节组成,字节数由宏
SOC_ADC_DIGI_RESULT_BYTES定义,其结构为adc_digi_output_data_t,包含 ADC 单元、ADC 通道与原始数据。
例如conv_frame_size = 100表示一个转换帧包含100 / SOC_ADC_DIGI_RESULT_BYTES个转换结果。该概念在 adc_continuous.h 头部注释中有完整图示说明。
4.2 资源分配:创建与回收驱动句柄
创建驱动前设置adc_continuous_handle_cfg_t(见 adc_continuous.h):
max_store_buf_size:内部缓冲池最大字节数,驱动将转换结果保存到该池;conv_frame_size:转换帧大小(字节),应为SOC_ADC_DIGI_DATA_BYTES_PER_CONV的倍数;flags.flush_pool:当缓冲池满时,自动冲刷旧数据并写入新数据;否则新转换结果将丢失。
adc_continuous_handle_t handle = NULL; adc_continuous_handle_cfg_t adc_config = { .max_store_buf_size = 1024, .conv_frame_size = 256, }; ESP_ERROR_CHECK(adc_continuous_new_handle(&adc_config, &handle));adc_continuous_new_handle()可能因参数非法、内存不足等失败。特殊地,返回ESP_ERR_NOT_FOUND的含义因芯片而异:ESP32 表示 I2S0 外设已被占用,ESP32-S2 表示 SPI3 已被占用,支持 GDMA 的芯片则代表没有空闲的 GDMA 通道。不再使用驱动时调用adc_continuous_deinit()反初始化。
4.3 通道与采样配置
初始化后,通过adc_continuous_config_t配置要采样的 IO(见 adc_continuous.h):
pattern_num:使用的 ADC 通道数量;adc_pattern:每个通道的配置列表,类型为adc_digi_pattern_config_t,包含atten(衰减)、channel(通道号)、unit(所属 ADC 单元)、bit_width(原始结果位宽);sample_freq_hz:期望的采样频率(Hz),可用的采样频率范围见soc/soc_caps.h;conv_mode:连续转换模式;format:转换输出格式(已标记 deprecated)。
调用adc_continuous_config()使配置生效。若返回ESP_ERR_INVALID_STATE,说明驱动已启动,此时不应再调用该 API。
4.4 启动与停止
ESP_ERROR_CHECK(adc_continuous_start(handle)); // 开始转换 ESP_ERROR_CHECK(adc_continuous_stop(handle)); // 停止转换4.5 注册事件回调
通过adc_continuous_register_event_callbacks()可将用户函数挂接到驱动 ISR,支持的回调定义于adc_continuous_evt_cbs_t:
on_conv_done:一个转换帧完成时触发;on_pool_ovf:内部缓冲池已满时触发,此时新转换结果将被丢弃(通常因为adc_continuous_read()读取速度远慢于 ADC 转换速度)。
回调在ISR 上下文中执行,因此回调内不能包含阻塞逻辑。事件数据adc_continuous_evt_data_t提供转换帧缓冲区指针conv_frame_buffer与大小size;注意该缓冲区由驱动自行维护,切勿手动 free。可通过user_data参数向回调传递用户上下文。当启用CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE时,回调及回调调用的函数须放置在 IRAM,涉及的变量也应放在内部 RAM。
4.6 读取与解析转换结果
adc_continuous_start()之后,调用adc_continuous_read()获取转换结果:
- 可请求读取指定长度的结果;若实际可用结果不足,函数仍会将内部池中的数据搬运到用户缓冲区,实际搬运长度通过
out_length返回; - 若内部池中暂无结果,函数会阻塞
timeout_ms毫秒直到至少产生一个结果,超时仍未产生则返回ESP_ERR_TIMEOUT; - 若结果填满内部池导致新结果丢失,下次调用将返回
ESP_ERR_INVALID_STATE。
continuous 模式读出的原始数据需进一步解析为结构化结果。ESP-IDF 提供两种方式:
方式一:adc_continuous_parse_data()手动解析
uint32_t ret_num = 0; esp_err_t ret = adc_continuous_read(handle, result, EXAMPLE_READ_LEN, &ret_num, 0); if (ret == ESP_OK) { adc_continuous_data_t parsed_data[ret_num / SOC_ADC_DIGI_RESULT_BYTES]; uint32_t num_parsed_samples = 0; esp_err_t parse_ret = adc_continuous_parse_data(handle, result, ret_num, parsed_data, &num_parsed_samples); if (parse_ret == ESP_OK) { for (int i = 0; i < num_parsed_samples; i++) { if (parsed_data[i].valid) { ESP_LOGI(TAG, "ADC%d, Channel: %d, Value: %"PRIu32, parsed_data[i].unit + 1, parsed_data[i].channel, parsed_data[i].raw_data); } } } }注意:raw_data_size必须是SOC_ADC_DIGI_RESULT_BYTES的整数倍,且raw_data缓冲区需足够容纳raw_data_size字节数据;解析函数内置了防缓冲区溢出与整数溢出的边界检查。
方式二:adc_continuous_read_parse()一步读取并解析
adc_continuous_data_t parsed_data[64]; // 用户指定最大样本数 uint32_t num_samples = 0; esp_err_t ret = adc_continuous_read_parse(handle, parsed_data, 64, &num_samples, 1000); if (ret == ESP_OK) { for (int i = 0; i < num_samples; i++) { if (parsed_data[i].valid) { ESP_LOGI(TAG, "ADC%d, Channel: %d, Value: %"PRIu32, parsed_data[i].unit + 1, parsed_data[i].channel, parsed_data[i].raw_data); } } }解析后的结构体adc_continuous_data_t(见 adc_continuous.h)包含:
unit:ADC 单元(ADC_UNIT_1 或 ADC_UNIT_2);channel:ADC 通道号(0-9);raw_data:ADC 原始数据值;valid:数据是否有效。
与 oneshot 模式相同,原始结果换算电压的公式为Vout = Dout × Vmax / Dmax,其中Dmax中的 bitwidth 对应adc_digi_pattern_config_t::bit_width。
4.7 IIR 滤波器与 Monitor 监视器
IIR 滤波器:支持SOC_ADC_DIG_IIR_FILTER_SUPPORTED的芯片在 continuous 模式下提供两个 IIR 滤波器。创建时需设置adc_continuous_iir_filter_config_t(包含unit、channel、coeff系数),调用adc_new_continuous_iir_filter()创建,adc_del_continuous_iir_filter()回收。在部分芯片上滤波器按 ADC 单元绑定(SOC_ADC_DIG_IIR_FILTER_UNIT_BINDED),一旦启用会对该单元所有已启用通道滤波,建议使用滤波功能时每单元只启用一个通道,避免滤波结果混合;启用/停用分别调用adc_continuous_iir_filter_enable()/adc_continuous_iir_filter_disable()。
Monitor 监视器:支持SOC_ADC_MONITOR_SUPPORTED的芯片可创建监视器(数量见SOC_ADC_DIGI_MONITOR_NUM),对工作通道设置一个或两个阈值,当转换结果超出阈值时在每个采样周期触发中断。配置结构体adc_monitor_config_t包含adc_unit、channel、h_threshold(高阈值,不用时置 -1)、l_threshold(低阈值,不用时置 -1)。操作 API 包括adc_continuous_monitor_enable/disable、adc_continuous_monitor_register_event_callbacks、adc_del_continuous_monitor。
monitor 的典型应用是过零检测:由于 ADC 无法直接处理负输入信号,需先通过电路叠加DC 偏置把负信号"平移"进 ADC 量程——例如叠加 1 V 偏置可将 -1 V ~ +1 V 的信号变换为 0 V ~ 2 V。随后设置合适的上下阈值,即可检测输入信号是否逼近零点,从而识别信号相位变化:
adc_monitor_handle_t adc_monitor_handle = NULL; adc_monitor_config_t zero_crossing_config = { .adc_unit = EXAMPLE_ADC_UNIT_1, // 指定要监视的 ADC 单元 .channel = EXAMPLE_ADC_CHANNEL_0, // 指定要监视的 ADC 通道 .h_threshold = 1100, // 高阈值,接近 DC 偏置值,可按需调整 .l_threshold = 900, // 低阈值,接近 DC 偏置值,可按需调整 }; ESP_ERROR_CHECK(adc_new_continuous_monitor(&zero_crossing_config, &adc_monitor_handle)); adc_monitor_evt_cbs_t zero_crossing_cbs = { .on_over_high_thresh = example_on_exceed_high_thresh, .on_below_low_thresh = example_on_below_low_thresh, }; ESP_ERROR_CHECK(adc_continuous_monitor_register_event_callbacks(adc_monitor_handle, &zero_crossing_cbs, NULL)); ESP_ERROR_CHECK(adc_continuous_monitor_enable(adc_monitor_handle)); // ... 使用完毕后停用并删除 ESP_ERROR_CHECK(adc_continuous_monitor_disable(adc_monitor_handle)); ESP_ERROR_CHECK(adc_del_continuous_monitor(adc_monitor_handle));4.8 continuous 模式的其他要点
- 电源管理:启用
CONFIG_PM_ENABLE后,系统空闲时 APB 时钟频率可能被调整,从而影响连续转换行为。continuous 驱动通过获取ESP_PM_APB_FREQ_MAX类型的电源管理锁来阻止该变化——锁在adc_continuous_start()后获取、adc_continuous_stop()后释放,因此两者必须成对出现,否则电源管理将失效。 - IRAM Safe:默认所有 continuous API 均非 IRAM-safe。启用
CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE后,驱动内部 ISR 处理器变为 IRAM-safe,即使 Cache 被禁用也能将转换结果保存到内部池。 - 线程安全:continuous 模式 API 不保证线程安全,但驱动提供共享硬件互斥保护。
五、ADC 校准驱动详解
由于不同芯片的实际参考电压存在 1000 mV ~ 1200 mV 的制造偏差,直接解读原始读数会产生较大误差。ADC 校准驱动通过软件修正偏差,输出更精确的结果。
5.1 校准方案(Scheme)的选择与创建
从校准驱动视角看,校准方案创建后得到一个校准句柄adc_cali_handle_t。可使用adc_cali_check_scheme()查询芯片支持的校准方案;若已知支持方案可跳过此步直接调用对应创建函数。芯片支持的方案由宏标识:
ADC_CALI_SCHEME_VER_LINE_FITTING(直线拟合):ESP32、ESP32-S2、ESP32-C2;ADC_CALI_SCHEME_VER_CURVE_FITTING(曲线拟合):ESP32-C3、ESP32-S3、ESP32-C6、ESP32-H2、ESP32-C5、ESP32-P4 等。
Line Fitting 方案:配置结构体adc_cali_line_fitting_config_t包含unit_id(原始结果来源 ADC)、atten(所用衰减)、bitwidth(原始结果位宽)。ESP32 上还有default_vref配置项,通常置 0 即可——Line Fitting 方案并不依赖该值;但若板子上未烧录方案所需的 eFuse 位,驱动将依赖该值完成校准。可用adc_cali_scheme_line_fitting_check_efuse()检查 eFuse 位状态:正常为ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP(两点值)或ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF(参考电压值);当为ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF时需设置default_vref。
ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting"); adc_cali_line_fitting_config_t cali_config = { .unit_id = unit, .atten = atten, .bitwidth = ADC_BITWIDTH_DEFAULT, }; ESP_ERROR_CHECK(adc_cali_create_scheme_line_fitting(&cali_config, &handle)); // ... 使用完毕后 ESP_ERROR_CHECK(adc_cali_delete_scheme_line_fitting(handle));Curve Fitting 方案:配置结构体adc_cali_curve_fitting_config_t同样包含unit_id、atten、bitwidth,以及为扩展性保留的chan字段。在 ESP32-C3 / ESP32-S3 上,校准只与衰减相关、与通道无关;而在 ESP32-C6 / ESP32-H2 / ESP32-C5 / ESP32-P4 上,校准不仅随衰减变化、还与通道相关,因此chan需填写原始结果来源通道。
ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting"); adc_cali_curve_fitting_config_t cali_config = { .unit_id = unit, .atten = atten, .bitwidth = ADC_BITWIDTH_DEFAULT, }; ESP_ERROR_CHECK(adc_cali_create_scheme_curve_fitting(&cali_config, &handle)); // ... 使用完毕后 ESP_ERROR_CHECK(adc_cali_delete_scheme_curve_fitting(handle));eFuse 相关失败:当创建函数返回ESP_ERR_NOT_SUPPORTED,说明校准方案所需的 eFuse 位未正确烧录。ESP-IDF 的校准方案基于片上特定 ADC 校准 eFuse 位,Espressif 保证这些位在模组制造时已烧录,用户无需自行烧录。若遇到此类错误,请联系官方技术支持渠道。
若想使用自定义校准方案,可参照 components/esp_adc/interface/adc_cali_interface.h 中的函数表adc_cali_scheme_t实现创建函数。
5.2 结果换算:raw → mV
校准特性设置完成后,调用adc_cali_raw_to_voltage()将原始结果转换为以 mV 为单位的校准结果:
int voltage[2][2]; ESP_ERROR_CHECK(adc_cali_raw_to_voltage(adc_cali_handle, adc_raw[0][0], &voltage[0][0])); ESP_LOGI(TAG, "ADC%d Channel[%d] Cali Voltage: %d mV", ADC_UNIT_1 + 1, EXAMPLE_ADC1_CHAN0, voltage[0][0]);若返回ESP_ERR_INVALID_STATE,说明校准方案句柄尚未创建,需先创建方案句柄(或用adc_cali_check_scheme()确认支持方案)。
注意(ESP32-C2):该校准仅支持
ADC_ATTEN_DB_0与ADC_ATTEN_DB_12两种衰减。0 dB 下衰减为 0 dB,不支持高于 950 mV 的输入电压;12 dB 下实际衰减为 11 dB,不支持高于 2800 mV 的输入电压。
5.3 线程安全
工厂函数adc_cali_check_scheme()及esp_adc_cali_new_scheme()由驱动保证线程安全;其他以adc_cali_handle_t为首参的函数不保证线程安全,应避免从多个任务同时调用。
5.4 降低噪声(Minimize Noise)
ADC 对噪声敏感,可能导致读数偏差较大。根据使用场景,可在使用的 ADC 输入引脚上连接旁路电容(例如 100 nF 陶瓷电容)来抑制噪声;此外多次采样(multisampling)也是一种有效的降噪手段。
上图展示了 ESP32 上通过旁路电容与 64 次多次采样组合后的噪声抑制效果。ESP32 上还可通过 Kconfig 选项裁剪校准代码体积:CONFIG_ADC_CALI_EFUSE_TP_ENABLE、CONFIG_ADC_CALI_EFUSE_VREF_ENABLE、CONFIG_ADC_CALI_LUT_ENABLE(若不用 12 dB 衰减下的校准可关闭查找表)。上述校准选项定义于 components/esp_adc/Kconfig。
六、硬件限制与注意事项汇总
| 芯片 | 限制说明 |
|---|---|
| 通用 | 同一 ADC 单元同一时刻只能工作于一种模式(oneshot 或 continuous),驱动已提供保护;RNG 随机数发生器以 ADC 为输入源,ADC 工作时 RNG 随机性下降 |
| 差分芯片(SOC_ADC_DIFF_SUPPORTED) | 单端模式下若以 N 侧通道作为输入接口,其原始数据极性反转(-2 V ~ 2 V 输入对应 N 侧原始码 4393 ~ 0),请使用校准 API 转换 |
| ESP32 / ESP32-S2 / ESP32-S3 | ADC2 同时被 Wi-Fi 使用,驱动已提供两者间的互斥保护 |
| ESP32-C3 | ADC2 oneshot 模式因硬件限制不再支持(结果不稳定,见芯片勘误表),可启用CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3强制使用 |
| ESP32-C3 / ESP32-S3 | ADC2 DMA 功能因硬件限制不再支持,可启用CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3强制使用 |
| ESP32 | continuous 驱动使用 I2S0 外设作为 DMA FIFO,I2S0 被占用时adc_continuous_new_handle()返回ESP_ERR_NOT_FOUND;ESP32-DevKitC 的 GPIO0 因自动下载电路不可用;ESP-WROVER-KIT 的 GPIO 0/2/4/15 不可用 |
| ESP32-S2 | continuous 驱动使用 SPI3 外设作为 DMA FIFO,被占用时同样返回ESP_ERR_NOT_FOUND |
相关 Kconfig 选项集中在 components/esp_adc/Kconfig:CONFIG_ADC_DISABLE_DAC_OUTPUT(ADC2 使用时默认禁用 DAC 输出)、CONFIG_ADC_ENABLE_DEBUG_LOG等。
七、示例工程与 API 参考
- examples/peripherals/adc/oneshot_read:演示使用 oneshot 驱动从 GPIO 读取单次 ADC 读数,并调用校准函数获得以 mV 为单位的校准结果;
- examples/peripherals/adc/continuous_read:演示在开发板上使用 continuous 模式(DMA)从 GPIO 引脚持续读取 ADC 数据。
两个示例均为可直接编译运行的完整工程,是学习两种驱动模式配置流程的最佳起点。
完整 API 参考(类型、配置结构体与函数文档)可进一步阅读:
- oneshot 模式 API(实现见 adc_oneshot.c)
- continuous 模式 API(实现见 adc_continuous.c)
- 校准驱动 API(实现见 adc_cali.c)
总结
ESP-IDF 的 ADC 驱动体系以"原始数据 + 校准换算"为设计核心:oneshot 模式以极简 API 覆盖低频按需采样场景,continuous 模式借助 DMA、转换帧、事件回调、IIR 滤波与阈值监视器等机制支撑高频连续采集,而校准驱动则通过 Line Fitting / Curve Fitting 两种方案将制造偏差修正到 mV 级精度。实际选型时,只需根据采样频率需求确定模式、依据信号幅度选择衰减档位,并牢记各芯片特有的硬件限制与电源管理、IRAM-safe 等约束,即可在 ESP32 全系列芯片上稳定、精确地完成模拟信号采集。
【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考