adc开发指南
本文档以 adc_demo.c 为例,带你在 HiDiTing 开发板上快速跑通第一个 ADC(模数转换器)控制应用,并了解如何基于它构建自己的应用。
ADC 驱动背景知识
ADC 工作原理
ADC(Analog-to-Digital Converter 模数转换器)实现对外部模拟信号转换成一定比例的数字值,从而实现对模拟信号的测量,可应用于电量检测、按键检测等,支持手动采样和自动扫描,功能场景如下:
| 功能 | 说明 | 应用场景 |
|---|---|---|
| 手动采样 | 通过软件触发单次采样,可配置采样次数和丢弃次数 | 电池电压检测、传感器数据采集 |
| 自动扫描 | 硬件自动连续采样,通过回调函数通知结果 | 连续波形采集、实时监控 |
| 通道选择 | 选择 ADC 通道进行采样(2/3) | 多路模拟信号采集 |
| 电压转换 | 将采样值转换为实际电压值 | 电压测量、信号分析 |
采样模式说明:
- 手动采样:通过 uapi_adc_manual_sample 接口触发单次采样,可配置采样次数(1-100000)和丢弃次数(0-10000),最终返回平均采样值和转换电压;ADC自动采样支持的采样频率有100Hz、200Hz、250Hz、500Hz、1000Hz。
-
自动扫描:通过 uapi_adc_auto_scan_ch_enable 接口启动硬件自动采样,采样结果通过回调函数返回,支持持续采样和单次采样模式。
-
注意事项:ADC 自动采样与手动采样互斥。自动采样需要开启宏
CONFIG_ADC_SUPPORT_AUTO_SCAN、CONFIG_ADC_SUPPORT_LONG_SAMPLE,手动采样需要关闭这两个宏。目标配置文件位于 /src/build/config/target_config/3322/menuconfig/acore,请按实际构建目标修改对应的.config文件。
操作流程
本示例支持手动采样和自动扫描两种操作模式,每种操作都遵循标准的初始化流程:
通用初始化步骤(所有操作共享):
- ADC 初始化:调用 uapi_adc_init(
ADC_CLOCK_500KHZ) 初始化 ADC 模块,设置时钟为 500KHz。 - 电源使能:调用 uapi_adc_power_en(
AFE_SCAN_MODE_MAX_NUM,true) 启用 ADC 电源。
各操作特有流程:
| 操作 | 流程 |
|---|---|
| 手动采样 | 禁用自动扫描 → 打开通道 → 丢弃指定次数采样 → 采集指定次数采样 → 计算平均值 → 转换为电压 → 关闭通道 → 禁用电源 |
| 启动自动扫描 | 启用电源 → 配置扫描参数 → 注册回调函数 → 使能自动扫描通道 |
| 停止自动扫描 | 设置停止标志 → 禁用自动扫描通道 |
接口说明:本示例基于AT命令框架实现,通过串口发送AT命令控制ADC,每个操作函数都封装了完整的初始化、配置、操作和验证流程。
通道与参数说明
| 参数 | 范围 | 说明 |
|---|---|---|
channel |
2/3 | ADC 通道号 |
sample_num |
1-100000 | 手动采样次数 |
sample_discard |
0-10000 | 手动采样丢弃次数 |
freq |
0-7 | 自动扫描频率配置 |
print_buffer |
0/1 | 是否打印缓冲区所有数据 |
continue_sample |
0/1 | 是否持续采样 |
API 接口列表
本文档示例代码中使用的接口:
| 接口函数 | 说明 |
|---|---|
| uapi_adc_init | 初始化 ADC 模块 |
| uapi_adc_deinit | 去初始化 ADC |
| uapi_adc_power_en | ADC 电源使能/禁用 |
| uapi_adc_open_channel | 打开 ADC 通道 |
| uapi_adc_close_channel | 关闭 ADC 通道 |
| uapi_adc_manual_sample | 手动采样 |
| uapi_adc_auto_scan_ch_enable | 启动自动扫描 |
| uapi_adc_auto_scan_ch_disable | 停止自动扫描 |
| uapi_adc_auto_scan_disable | 禁用自动扫描 |
| uapi_adc_auto_scan_is_enabled | 查询自动扫描状态 |
完整 API 列表
更多 ADC 接口请参考:ADC API 参考
快速跑通 ADC Demo
功能说明
ADC Demo 通过 AT 命令方式提供交互式控制,支持以下命令:
| AT 命令 | 功能 | 参数说明 |
|---|---|---|
AT+GETADCDEMOMANUAL=channel,sample_num,sample_discard |
ADC 手动采样 | channel: 通道号(2/3), sample_num: 采样次数(1-100000), sample_discard: 丢弃次数(0-10000) |
AT+STARTADCDEMOAUTO=channel,freq,print_buffer,continue_sample |
启动 ADC 自动扫描 | channel: 通道号(2/3), freq: 频率(0-7), print_buffer: 是否打印(0-1), continue_sample: 是否持续(0-1) |
AT+STOPADCDEMOAUTO=channel |
停止 ADC 自动扫描 | channel: 通道号(2/3) |
编译
完成一站式 CLI 环境配置后执行:
# 编译固件,编译生成的固件从 output/3322/fwpkg 中获取 diting-community.fwpkg
fbb set-target pack_diting_community
fbb build
构建成功后,使用一站式 CLI 烧写固件并打开 UART2 串口监视器。以下为 Windows USB DFU 示例;将 COM3 替换为实际日志串口,其他平台和串口烧写参数参见一站式 CLI 开发环境使用指南。
fbb flash -f "$env:FBB_SDK_DIR\output\3322\fwpkg\diting-community.fwpkg" --chip 3322 -d --timeout 180
fbb monitor --port COM3 --baud 750000
使用方式
- 烧录固件并启动设备。
- 找到adc通道引脚,用可调电源正极给要测试的引脚输入直流电源(不超过1.8V),负极接地:本示例是以adc通道2,输入1.2V电压为例测试。
-
通过串口发送 AT 命令,格式如下:

预期结果
ADC 手动采样(AT+GETADCDEMOMANUAL)

ADC 启动自动扫描(AT+STARTADCDEMOAUTO)

ADC 停止自动扫描(AT+STOPADCDEMOAUTO)

文件结构与代码走读
文件职责
| 文件 | 作用 |
|---|---|
| samples/native_samples/adc/CMakeLists.txt | 定义 adc_sample 组件、依赖头文件和 AT 适配宏。 |
| samples/native_samples/adc/adc_demo.h | 定义串口测试参数结构、参数约束和命令表。 |
| samples/native_samples/adc/adc_demo.c | 实现手动采样、自动扫描、结果统计和资源释放。 |
| samples/native_samples/adc/README.md | 给出完整命令、参数和预期日志。 |
完整实现以以上 Sample 源文件为准,本文只说明业务必须理解的参数和调用顺序。
关键参数与状态
| 名称 | 作用 | 开发注意事项 |
|---|---|---|
channel |
选择 ADC 通道。当前示例验证通道 2、3。 | 应同时确认芯片通道和板级引脚复用关系。 |
sample_num / sample_discard |
控制有效采样数和前置丢弃次数。 | 丢弃采样可减小切换通道后的瞬态影响;缓冲区大小必须按采样数检查。 |
adc_scan_config_t.freq |
设置自动扫描频率档位。 | 档位是驱动枚举,不应直接当作 Hz 使用。 |
g_adc_continue_sample |
决定自动扫描回调后是否继续。 | 停止业务时先清除此状态,再关闭对应通道。 |
CONFIG_ADC_SUPPORT_AUTO_SCAN |
控制自动扫描代码是否参与构建。 | 手动采样与自动扫描互斥,修改目标配置后重新构建。 |
adc_manual_args_t、adc_start_auto_args_t 和 adc_stop_auto_args_t 只负责把串口参数传给上述业务流程;自定义应用不需要复制 AT 参数结构和命令表。
核心业务流程
手动采样流程
- 使用
uapi_adc_init()初始化 ADC,并确认自动扫描未占用 ADC。 - 调用
uapi_adc_power_en()上电,再用uapi_adc_open_channel()打开目标通道。 - 按需丢弃前几次结果,循环调用
uapi_adc_manual_sample()获取有效样本。 - 统计有效样本并通过
adc_port_stick_transfer_voltage()换算电压。 - 无论采样成功还是失败,都关闭通道并关闭 ADC 电源。
自动扫描流程
- 初始化并上电,填写
adc_scan_config_t,注册采样回调。 - 调用
uapi_adc_auto_scan_ch_enable()启动通道;回调按length处理缓冲区,不保存回调结束后失效的地址。 - 回调通过
next决定是否继续;停止业务时调用uapi_adc_auto_scan_ch_disable()。
AT 命令仅用于快速触发和板端回归,命令注册、日志拼装与上述驱动流程解耦。自定义应用的可构建 app_run 入口见下一节。
基于 ADC Demo 开发自己的应用
上面的demo是使用AT指令触发运行,HiDiTing还支持app_run方式触发应用在系统启动时自动运行,以下示例将以app_run的方式开发一个开发者自己的应用
- app_run(func) 是HiDiTing中应用层注册应用函数的宏,基于 GCC 编译器属性和自定义段区(section)自动注册来实现集中调用应用函数,系统启动时会自动遍历所有用 app_run 注册过的函数并执行,无需在系统 main 函数里逐个调用函数。
代码清单
新建一个 ADC 控制应用(以 my_adc_demo 为例)通常只需要以下改动:
- 新建
my_adc_demo.c源文件 - 新建
my_adc_demo.h头文件 - 新建
CMakeLists.txt源文件 - 在
my_adc_demo.c中实现ADC操作函数 - 在
my_adc_demo.h中定义宏常量和函数声明 - 在
CMakeLists.txt源文件编译规则
my_adc_demo文件结构:
CMakeLists.txt 修改示例
# 在新建的 CMakeLists.txt 中添加应用的源文件
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/my_adc_demo.c
)
set(PUBLIC_HEADER
${CMAKE_CURRENT_SOURCE_DIR}
)
set(PRIVATE_HEADER
)
set(PUBLIC_DEFINES
MY_ADC_DEMO_ENABLE
)
build_component()
关键代码片段
my_adc_demo.c —— ADC 控制实现
#include <stdio.h>
#include <string.h>
#include "errcode.h"
#include "adc_porting.h"
#include "adc.h"
#include "my_adc_demo.h"
#define ADC_TEST_CHANNEL 2 // 测试使用的通道号
#define ADC_SAMPLE_NUM 10 // 采样次数
#define ADC_SAMPLE_DISCARD 2 // 丢弃次数
#define TASK_PRIO 26
#define TASK_STACK_SIZE 0x1000
static void *my_adc_task(const char *arg)
{
unused(arg);
printf("my_adc_demo start\n");
// step1: 初始化ADC,设置时钟为500KHz
uapi_adc_init(ADC_CLOCK_500KHZ);
#if defined(CONFIG_ADC_SUPPORT_AUTO_SCAN)
// step2: 禁用自动扫描模式
uapi_adc_auto_scan_disable();
#endif
// step3: 启用ADC电源
uapi_adc_power_en(AFE_SCAN_MODE_MAX_NUM, true);
// step4: 打开指定通道
errcode_t ret = uapi_adc_open_channel(ADC_TEST_CHANNEL);
if (ret == ERRCODE_SUCC) {
printf("adc open channel success\n");
// step5: 丢弃指定次数的采样结果
for (uint32_t i = 0; i < ADC_SAMPLE_DISCARD; i++) {
(void)uapi_adc_manual_sample(ADC_TEST_CHANNEL);
uapi_tcxo_delay_ms(3);
}
// step6: 执行采样
uint32_t stick = 0;
for (uint32_t i = 0; i < ADC_SAMPLE_NUM; i++) {
uint16_t sample = (uint16_t)uapi_adc_manual_sample(ADC_TEST_CHANNEL);
printf("sample[%d] = %d\n", i, sample);
stick += sample;
}
// step7: 计算平均值并转换为电压
stick = stick / ADC_SAMPLE_NUM;
float voltage = adc_port_stick_transfer_voltage((uint16_t)stick);
printf("average tick: %d, voltage: %.4f\n", stick, voltage);
} else {
printf("uapi_adc_open_channel failed=%d\r\n", ret);
}
// step8: 关闭通道并禁用电源
uapi_adc_close_channel(ADC_TEST_CHANNEL);
uapi_adc_power_en(AFE_SCAN_MODE_MAX_NUM, false);
printf("my_adc_demo done\n");
return NULL;
}
static void my_adc_entry(void)
{
osal_task *task_handle = NULL;
osal_kthread_lock();
task_handle = osal_kthread_create((osal_kthread_handler)my_adc_task, 0, "MyAdcTask", TASK_STACK_SIZE);
if (task_handle != NULL) {
osal_kthread_set_priority(task_handle, TASK_PRIO);
}
osal_kthread_unlock();
}
app_run(my_adc_entry);
测试验证
完成一站式 CLI 环境配置后执行:
# 编译固件,编译生成的固件从 output/3322/fwpkg 中获取 diting-community.fwpkg
fbb set-target pack_diting_community
fbb build
- 烧录固件并启动设备
- 通过串口观察输出日志:
说明
- 因为
app_run是在系统启动时运行应用,所以应用的运行日志会被夹在开机启动日志中。 - 为使该
adc应用参与编译,还需在上层CMakeLists.txt文件中以宏MY_ADC_DEMO_ENABLE为条件添加该my_adc_demo文件。 - 宏
MY_ADC_DEMO_ENABLE默认关闭。如需启用新建ADC示例功能,需要在config.py中的diting-community配置项下将其打开。
app_run运行配置
app_run应用默认是关闭的,如需启用此应用,需用户手动在acore.prelds文件中添加 KEEP (*(SORT(.zinitcall.app_run*.init))) 具体参考示意图如下:

注意事项
ADC 初始化注意事项:
- 使用前必须调用
uapi_adc_init(ADC_CLOCK_500KHZ)完成 ADC 初始化。 - 必须调用
uapi_adc_power_en(AFE_SCAN_MODE_MAX_NUM, true)启用 ADC 电源。 - 采样完成后必须调用
uapi_adc_close_channel()关闭通道,并调用uapi_adc_power_en(AFE_SCAN_MODE_MAX_NUM, false)禁用电源。
手动采样注意事项:
- 手动采样前建议先丢弃若干次采样结果,以消除初始采样不稳定带来的误差。
- 采样结果中值为 0 的数据会被视为无效数据并自动排除。
- 采样间隔至少为 3ms,以确保采样稳定性。
自动扫描注意事项:
- 自动扫描功能需要硬件支持,通过宏
CONFIG_ADC_SUPPORT_AUTO_SCAN控制。 - 启动自动扫描前需要先初始化 ADC 并启用电源。
- 回调函数中通过
*next参数控制是否继续采样。 - 停止自动扫描时,需要先设置
g_adc_continue_sample = false,再禁用通道。
AT 命令注意事项:
- 命令名称为大写字母,如
GETADCDEMOMANUAL。 - 参数使用逗号分隔,如
AT+GETADCDEMOMANUAL=2,10,2。 - 参数范围:channel 为 2/3,sample_num 为 1-100000,sample_discard 为 0-10000。
常见错误
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
undefined reference to 'uapi_adc_init' |
未链接 ADC 驱动库 | 检查 CMakeLists.txt 中是否正确添加了头文件路径 |
undefined reference to 'uapi_at_cmd_table_register' |
未链接 AT 命令库 | 检查 CMakeLists.txt 中是否正确添加了 AT 相关头文件路径 |
编译报 at_ret_t 未定义 |
未包含 at.h 头文件 |
添加 #include "at.h" |
| 串口无输出 | AT 命令未注册 | 确认调用了 at_diting_adc_example_cmd_register() |
| 采样结果全为 0 | ADC 通道未正确打开或电源未使能 | 确认依次调用了 uapi_adc_init()、uapi_adc_power_en()、uapi_adc_open_channel() |
| 自动扫描无回调 | 自动扫描功能未启用 | 确认宏 CONFIG_ADC_SUPPORT_AUTO_SCAN 已定义 |