Skip to content

由 爱笑 贡献,Ai-Thinker 进行整理

【Ai-WB2中级篇】ADC模数转换

模数转换器(analog-to-diaital converter,通常称为ADC)是一种模拟与数字转换器,支持12路外部模拟输入和若干内部模拟信号选择。 Ai-WB2的ADC支持以下四种模式:单次单诵道转换、连续单诵道转换、单次多通道转换和连续多通道转换模式。转换结果为1214116bits左对齐模式。ADC拥有深度为32的FIFO,支持多种中断和DMA操作。 ADC除了用于普通模拟信号测量外,还可以用于测量供电电压,比外ADC还可以通过测量内/外部二极管电压用于温度检测。

本文将详细介绍如何通过Ai-WB2的ADC模块对电位计进行电压采样。 一:ADC介绍 BL602芯片内置一个12bits 的逐次逼近式模拟数字转换器(ADC),支持12 路外部模拟输入和若干内部模拟信号选择。ADC可以工作在单次转换和多通道扫描两种模式下,转换结果为12/14/16bits左对齐模式。ADC 拥有深度为32的FIFO,支持多种中断,支持DMA 操作。ADC 除了用于普通模拟信号测量外,还可以用于测量供电电压,此外ADC 还可以通过测量内/外部二极管电压用于温度检测。 Ai-WB2的ADC具有如下特性:

📜 点击展开完整代码
c
**高性能**
**·** 可以选择12-bit,14-bit,16-bit 转换结果输出
**·** ADC 转换时间最快0.5us(12-bit 转换结果)
**·** 支持1.8V3.3V 可选参考电压
**·** 支持DMA 将转换结果搬运到内存
**·** 支持单通道转换和多通道扫描两种模式
**·** 支持单端与差分两种输入模式
**·** 支持抖动补偿
**·** 支持用户自行设定转换结果偏移值
**·** 扫描模式时钟最大支持1M,非扫描模式支持2M
**模拟通道数**
**·** 12 路外部模拟通道
**·** 2 路DAC 内部通道
**·** 1路VBAT/2 通道
**·** 1路TSEN 通道

ADC的功能框图如下:

ADC 模块包含五大部分,分别为前端输入通道选择器,程控放大器,ADC 采样模块,数据处理模块以及FIFO。输入通道选择器用于选择需要采样的通道,既包含外部模拟信号,也包含内部模拟信号,程控放大器用于对输入信号做进一步处理,可以根据输入信号的特点,比如直流,交流,进行设定,以便得到更准确的转换值。ADC 采样模块是最主要的功能模块,实现通过逐次比较的方式,得到模拟信号到数字信号的转换。转换的结果为12bit,数据处理模块负责将转换的结果进一步处理,包括添加通道信息等。最后得到的数据会推送到最后端的FIFO 中。

BL602中,ADC通道与GPIO的对应关系如下:

二:ADC驱动API 在bl_iot_sK中,ADC的HOSAL层高级APl在 components/platform/hosal/include/hosal_adc.h中定义。常用的驱动API函数如下: · int hosal_adc_init(hosal_adc_dev_t *adc):初始化ADC。参数说明如下: · adc:ADC设备。其定义如下:

📜 点击展开完整代码
c
/**
* @brief Define ADC dev hosal handle
*/
typedef struct {
uint8_t port;                    /**< @brief adc 端口 */
hosal_adc_config_t config;        /**< @brief adc 配置 */
hosal_dma_chan_t dma_chan;        /**< @brief adc dma 通道 */
hosal_adc_irq_t cb;               /**< @brief adc 回调函数 */
void *p_arg;                      /**< @brief p_arg 回调函数参数 */
void *priv;                       /**< @brief priv 用户自定义数据 */
} hosal_adc_dev_t;

其中,hosal_adc_config_t为ADC配置,其定义如下:

📜 点击展开完整代码
c
/**
* @brief Define ADC config args
*/
typedef struct {
uint32_t sampling_freq;             /**< @brief 采样频率(以Hz为单位) */
uint32_t pin;                        /**< @brief adc 引脚 */
hosal_adc_sample_mode_t mode;       /**< @brief adc 采样模式 */
uint8_t sample_resolution;          /**< @brief adc 采样精度 */
} hosal_adc_config_t;

其中hosal_adc_sample_mode_t的定义如下:

📜 点击展开完整代码
c
/**
* @brief ADC MODE type
*/
typedef enum {
HOSAL_ADC_ONE_SHOT,       /**< @brief 单次采样 */
HOSAL_ADC_CONTINUE        /**< @brief 持续采样 */
} hosal_adc_sample_mode_t;
📜 点击展开完整代码
c
**·** 返回值:成功时返回0,否则返回EIO或其他值
**·** int hosal_adc_add_channel(hosal_adc_dev_t *adc,uint32_t channel):添加向ADC设备添加ADC通道。参数说明如下:
**·** adc:ADC端口设备
**·** ochannel:需要添加的ADC通道
**·** 返回值:成功时返回0,否则返回EIO或其他值
**·** int hosal_adc_remove_channel(hosal_adc_dev_t *adc, uint32_t channel):移除ADC诵道。参数说明如下:
**·** adc:ADC端囗设备
**·** ochannel:需要移除的ADC通道
**·** 返回值:成功时返回0,否则返回EIO或其他值
**·** int hosal_adc_value_get(hosal_adc_dev_t *adc, uint32_t channel,uint32_t timeout):读取单个ADC采样结果。参数说明如下:
**·** adc:ADC端口设备
**·** channel:ADC通道
**·** otimeout:超时时长
**·** 返回值:如果读取失败,则返回-1:否则返回ADC值
**·** int hosal_adc_tsen_value_get(hosal_adc_dev_t*adc):获取ADC端囗的TSEN值。参数说明如下:
**·** adc:ADC端口设备
**·** 返回值:如果读取失败,则返回-1:否则返回ADC值
**·** int hosal_adc_sample_cb_reg(hosal_adc_dev_t *adc,hosal_adc_cb_t cb):注册ADC回调函数(该函数未具体实现)
**·** adc:ADC端口设备
**·** cb:回调函数,当cb不为NULL时,表示注册;当cb为NULL时,表示注销。其定义如下:
  1. typedef void (*hosal_adc_irq_t)(void *parg);

请注意:指针cb 中的 adc 必须与传递给 hosal_adc_sample_cb_reg 的 adc 指针相同,驱动程序必须通过调用 cb 通知上层 ADC 数据是否已在硬件或内存(DMA)中准备好。

📜 点击展开完整代码
c
**·** 返回值:成功时返回0,否则返回EIO或其他值
**·** int hosal_adc_start(hosal_adc_dev_t *adc,void *data,uint32_t size):启动ADC采样(该函数未具体实现)。参数说明如下:
**·** adc:ADC端口设备
**·** data:用于储存采样结果
**·** size:储存ADC采样结果长度
**·** 返回值:成功时返回0,否则返回EIO或其他值
**·** int hosal adc_stop(hosal_adc_dev_t *adc):ADC停止采样(该函数未具体实现)。参数说明如下:
**·** adc:ADC端口设备
**·** 返回值:成功时返回0,否则返回EIO或其他值
**·** hosal_adc_finalize(hosal_adc_dev_t *adc):释放ADC。参数说明如下:
**·** adc:ADC端囗设备
**·** 返回值:成功时返回0,否则返回EIO或其他值
**三:ADC使用示例**

下面将演示通过ADC的通道4(GPIO5)来对电位计的电压进行采样。示例代码如下:

📜 点击展开完整代码
c
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <stdio.h>
#include <stdbool.h>
#include <hosal_dma.h>
#include <hosal_adc.h>
#include <blog.h>
#define TAG "adc_demo"
/**********   BL602  ************
*    channel0   ----->     gpio12
*    channel1   ----->     gpio4
*    channel2   ----->     gpio14
*    channel3   ----->     gpio13
*    channel4   ----->     gpio5
*    channel5   ----->     gpio6
*    channel7   ----->     gpio9
*    channel9   ----->     gpio10
*    channel10  ----->     gpio11
*    channel11  ----->     gpio15
*/
static hosal_adc_dev_t adc0;
static void adc_init(void){
adc0.port = 0;
adc0.config.sampling_freq = 340;
adc0.config.pin = 5;
adc0.config.mode = HOSAL_ADC_ONE_SHOT; // 配置为单次采样
int ret = hosal_adc_init(&adc0);
if (ret != 0) {
blog_error("init adc failed. \r\n");
return;
}
hosal_adc_add_channel(&adc0, 4);
printf("adc init done\r\n");
}
void adc_task(void* params){
adc_init();
printf("adc task start...\r\n");
vTaskDelay(500);
while(true){
//hosal_adc_start(&adc0);
int ret = hosal_adc_value_get(&adc0, 4, 20);
if(ret < 0){
printf("adc sample failed:%d\r\n",ret);
continue;
}
printf("adc value = %d\r\n",ret);
vTaskDelay(10);
}
hosal_adc_finalize(&adc0);
}
void main(void) {
hosal_dma_init();
printf("adc demo inited\r\n");
xTaskCreate(adc_task, "adc_task", 1024, NULL, 15, NULL);
}

注意:HOSAL层使用了DMA方式采样,因此需要调用 hosal_dma_init 函数来初始化DMA模块。

Released under the MIT License. Build Time 2026-09-11 14:52:23