ESP32外设-4.ADC入门
说明:
- 本文档由DuRuofu撰写,由DuRuofu负责解释及执行。
- 本文档介绍ADC外设的使用,个人记录使用,如有侵权请联系删除。
修订历史:
文档名称 | 版本 | 作者 | 时间 | 备注 |
---|---|---|---|---|
ESP32外设-ADC入门 | v1.0.0 | DuRuofu | 2024-03-03 | 首次建立 |
ESP32外设-ADC入门
本文档主要转载自Augtons正(单片机)的ESP32系列教程(关于ADC部分的梳理甚至比官方教程都清晰)。
一、介绍
ESP32(经典版)集成了两个 12
位SAR(逐次逼近寄存器)adc,共支持18个测量通道。
- 采用 2 个 SAR ADC,可支持同时采样与转换
- 采用 5 个专用 ADC 控制器,可支持不同应用场景(比如,高性能、低功耗,或功率检测和峰值检测)
- 支持 18 个模拟输入管脚
- 可配置 12 位、11 位、10 位、9 位多种分辨率
- 支持 DMA(1 个控制器支持)
- 支持多通道扫描模式(2 个控制器支持)
- 支持 Deep-sleep 模式运行(1 个控制器支持)
- 支持 ULP 协处理器控制(2 个控制器支持)
1.1 ADC通道概览
ADC1:
支持 8 个通道,包括:GPIO32 - GPIO39(并非按顺序)
ADC2:支持 10 个通道,包括:GPIO0, GPIO2, GPIO4, GPIO12 - GPIO15, GOIO25 - GPIO27(并非按顺序)
ESP32 内置霍尔传感器,采用 ADC1 的通道0和3(GPIO36 和 GPIO39)。
注意:
ADC2
模块也被Wi-Fi
使用,当它们一起使用时,只有一个会被抢占,这意味着adc2_get_raw()
可能会被阻塞,直到Wi-Fi
停止,反之亦然。换言之,ADC2 不能与 WIFI 共用!- 从一个没有连接到任何信号的引脚读取到的 ADC 值是 随机 的。
ADC通道对应关系如下(经典模组):
1 |
|
1.2 ADC 衰减
ADC模块 能读取电压的范围(量程)有限,因此我们一般给某个 ADC 通道配置一定的衰减,使其读取更大的电压。但更大的量程会导致更小的精度。因此根据 ADC 的应用场景,选择适当的衰减级别十分必要。
ESP32 的每一个通道都有提供了4个级别的衰减等级,不同的衰减等级对于的量程在下表列出:注意,下表中的 “推荐范围” 并不是量程 ,而是在某衰减等级下测量最精确的推荐测量范围
1.2 ADC校准与减小测量误差
减少噪声
ESP32 ADC 对噪声敏感,可能导致 ADC 读数出现较大偏差。根据不同使用场景,要减少噪声影响,你可能需要将旁路电容(如 100 nF 陶瓷电容)连接到 ADC 使用的输入管脚。此外,也可以通过多次采样,进一步减轻噪声的影响。
图中展示了连接电容以及 64 次采样对噪声的抑制效果。其中纵轴(ADC Reading)代表不同方式读取到的ADC值,横轴(Sample Number)是采样次数。
ADC 校准
关于ADC校准的库为esp_adc_cal.h
1 |
|
个库提供 API 函数用于校正基准ADC 参考电压,ADC参考电压为 1100 m V。
对于不同的参考电压,ADC 值与输入电压值(待测电压)的关系不同。关系如下图:
上图列出了参考电压分别在:V r e f = =1070mV(蓝色) 和 V r e f = =1160mV(橙色) 下的 ADC 值和待测电压 Voltage 的关系。
我们把这条拟合曲线称为 ADC 模块(在某参考电压下)的 ADC-Voltage 特征曲线。
在实际应用中,我们调用esp_adc_cal.h库提供的 API 函数去求得指定参考电压下的 ADC-Voltage 特征曲线,并利用这一条曲线去将 ADC 测量值转换为欲测量的电压Voltage。开发者可以选择自定义参考电压值,也可以利用ESP32 内部 eFuse(一次性可编程存储器)中储存的出厂参考电压校准值去获取这个曲线。
使用下面的命令:
1 |
|
效果:
除此之外,ESP32 内部的参考电压也可以手动测量,方法是将此电压输出到(路由到)某个GPIO口上,然后手动测量此GPIO口和GND接口之间的电压,就是eFuse内部的参考电压。将参考电压路由到GPIO的方法是调用API函数adc_vref_to_gpio(),参数是想要输出电压的GPIO口编号。必须是ADC2的通道IO口之一,因为ESP32只支持将参考电压路由到 ADC2 上
1 |
|
二、使用
单次转换模式使用
1、 资源分配 :获取 ADC 句柄,以及回收资源
需要配置结构体 adc_oneshot_unit_init_cfg_t
参数为:
adc_oneshot_unit_init_cfg_t::unit_id
选择 ADC。adc_oneshot_unit_init_cfg_t::clk_src
选择 ADC 的时钟源。设置为 0 时,驱动程序将使用默认时钟源,详情请参阅adc_oneshot_clk_src_t
。adc_oneshot_unit_init_cfg_t::ulp_mode
设置是否支持 ADC 在 ULP 模式下工作。
完成 ADC 初始配置后,使用已设置的初始配置结构体 adc_oneshot_unit_init_cfg_t
调用 adc_oneshot_new_unit()
。如果分配成功,该函数将返回 ADC 单元实例句柄。
该函数可能因参数无效、内存不足等原因返回错误代码。比如,当要分配的 ADC 实例已经注册时,该函数会返回 ESP_ERR_NOT_FOUND
错误。可用 ADC 数量可通过 SOC_ADC_PERIPH_NUM
查看
如果不再需要先前创建的 ADC 单元实例,请调用 adc_oneshot_del_unit()
回收该实例,相关的硬件和软件资源也会回收。
创建 ADC 单元实例句柄示例:
1 |
|
回收 ADC 单元实例示例
1 |
|
2、 配置 ADC 单元实例
设置 adc_oneshot_chan_cfg_t
配置 ADC IO 以测量模拟信号
参数:
adc_oneshot_chan_cfg_t::atten
,ADC 衰减。adc_oneshot_chan_cfg_t::bitwidth
,原始转换结果的位宽。
使用上述配置结构体调用 adc_oneshot_config_channel()
,并指定要配置的 ADC 通道。函数 adc_oneshot_config_channel()
支持多次调用,以配置不同的 ADC 通道。驱动程序将在内部保存每个通道的配置。
示例:配置两个 ADC 通道
1 |
|
3、 读取转换结果
调用 adc_oneshot_read()
可以获取 ADC 通道的原始转换结果。
通过该函数获取的 ADC 转换结果为原始数据。可以使用以下公式,根据 ADC 原始结果计算电压:
1 |
|
Vout | 数字输出结果,代表电压。 |
---|---|
Dout | ADC 原始数字读取结果。 |
Vmax | 可测量的最大模拟输入电压,与 ADC 衰减相关,请参考 技术参考手册 > 片上传感器与模拟信号处理 。 |
Dmax | 输出 ADC 原始数字读取结果的最大值,即 2^位宽,位宽即之前配置的 adc_digi_pattern_config_t::bit_width 。 |
读取原始结果示例: |
1 |
|
注:
- 随机数生成器 (RNG) 以 ADC 为输入源。使用 ADC 单次转换模式驱动从 RNG 生成随机数时,随机性会减弱。
- 一个 ADC 单元每次只能在一种操作模式下运行,可以是连续模式或单次模式。
adc_oneshot_start()
提供了保护措施。- Wi-Fi 也使用 ADC2,
adc_oneshot_read()
提供了 Wi-Fi 驱动与 ADC 单次转换模式驱动间的保护。- ESP32-DevKitC:GPIO0 已用于自动烧录功能,不能用于 ADC 单次转换模式。
- ESP-WROVER-KIT:GPIO0、GPIO2、GPIO4 和 GPIO15 已有其他用途,不能用于 ADC 单次转换模式。
连续转换模式使用
ADC 连续转换模式驱动由多个转换帧组成。
- 转换帧:一个转换帧包含多个转换结果。转换帧大小以字节为单位,在
adc_continuous_new_handle()
中配置。 - 转换结果:一个转换结果包含多个字节,即
SOC_ADC_DIGI_RESULT_BYTES
。转换结果的数据结构由adc_digi_output_data_t
定义,包括 ADC 单元、ADC 通道以及原始数据。
1、 资源分配:
首先设置配置结构体 adc_continuous_handle_cfg_t
,创建 ADC 连续转换模式驱动的句柄,参数如下:
adc_continuous_handle_cfg_t::max_store_buf_size
:以字节为单位设置最大缓冲池的大小,驱动程序将 ADC 转换结果保存到该缓冲池中。缓冲池已满时,新的转换将丢失。adc_continuous_handle_cfg_t::conv_frame_size
:以字节为单位设置 ADC 转换帧大小。adc_continuous_handle_cfg_t::flags
:设置可以改变驱动程序行为的标志。(flush_pool
:缓冲池满时自动清空缓冲池。)
完成以上 ADC 配置后,使用已设置的配置结构体 adc_continuous_handle_cfg_t
调用 adc_continuous_new_handle()
来分配资源。
如果不再使用 ADC 连续转换模式驱动,请调用 adc_continuous_deinit()
将驱动去初始化。
配置示例:
1 |
|
2、 配置 ADC:
初始化 ADC 连续转换模式驱动后,设置 adc_continuous_config_t
配置 ADC IO,测量模拟信号:
adc_continuous_config_t::pattern_num
:要使用的 ADC 通道数量。adc_continuous_config_t::adc_pattern
:每个要使用的 ADC 通道的配置列表,请参阅下文描述。adc_continuous_config_t::sample_freq_hz
:期望的 ADC 采样频率,单位为 Hz。adc_continuous_config_t::conv_mode
:连续转换模式。adc_continuous_config_t::format
:转换模式结果的输出格式。
adc_digi_pattern_config_t::atten
:ADC 衰减。请参阅 技术参考手册 中的片上传感器与模拟信号处理章节。adc_digi_pattern_config_t::channel
:IO 对应的 ADC 通道号,请参阅下文注意事项。adc_digi_pattern_config_t::unit
:IO 所属的 ADC 单元。adc_digi_pattern_config_t::bit_width
:原始转换结果的位宽。
最后,使用上述配置结构体,调用 adc_continuous_config()
。
配置示例:
1 |
|
3、 ADC 控制:
调用 adc_continuous_start()
,将使 ADC 开始从配置好的 ADC 通道测量模拟信号,并生成转换结果。
调用 adc_continuous_stop()
则会停止 ADC 转换。
4、注册事件回调:
调用 adc_continuous_register_event_callbacks()
,可以将自己的函数链接到驱动程序的 ISR 中。通过 adc_continuous_evt_cbs_t
可查看所有支持的事件回调。
adc_continuous_evt_cbs_t::on_conv_done
:当一个转换帧完成时,触发此事件。adc_continuous_evt_cbs_t::on_pool_ovf
:当内部缓冲池已满时,触发此事件,新的转换结果将丢失。
转换完成事件
当驱动程序完成一次转换后,会触发 adc_continuous_evt_cbs_t::on_conv_done
事件,并填充事件数据。事件数据包含一个指向转换帧缓冲区的指针,以及转换帧缓冲区大小。要了解事件数据结构,请参阅 adc_continuous_evt_data_t
。
5、读取转换结果:
调用 adc_continuous_start()
启动 ADC 连续转换,调用 adc_continuous_read()
可以获取 ADC 通道的转换结果。注意提供缓冲区,获取原始结果。
函数 adc_continuous_read()
每次都会尝试以期望长度读取转换结果。
参数:
- handle – [in] ADC连续模式驱动句柄
- buf – **[out]**要从ADC读取的转换结果缓冲区。
- length_max – [in] 从ADC读取的转换结果的预期长度(以字节为单位)。
- out_length – [out] 通过此API从ADC读取的转换结果的实际长度(以字节为单位)。
- timeout_ms – [in] 通过此API等待数据的时间(以毫秒为单位)。
六、ADC 示例
单次转换示例程序:
1 |
|
为通道6接上1V电压:
串口输出结果:
连续转换示例程序:
1 |
|
接线:
效果:
参考链接
- https://blog.csdn.net/m0_50064262/article/details/118817032
- https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/adc_oneshot.html#_CPPv427adc_oneshot_unit_init_cfg_t
- extension://bfdogplmndidlpjfhoijckpakkdjkkil/pdf/viewer.html?file=https%3A%2F%2Fwww.espressif.com%2Fsites%2Fdefault%2Ffiles%2Fdocumentation%2Fesp32_technical_reference_manual_cn.pdf
- https://github.com/espressif/esp-idf/tree/fdb7a43/examples/peripherals/adc/oneshot_read