timer开发指南
本文档以 timer_demo 为例,带你在 HiDiTing 开发板上快速跑通第一个 timer(定时器)应用,并了解如何基于它构建自己的应用。
timer 驱动背景知识
timer 工作原理
timer 是用于生成周期性或单次定时信号的硬件模块,主要功能包括:
- 生成周期性中断(用于系统心跳、任务调度)
- 生成单次定时事件(用于延时、超时检测)
操作流程
本示例支持定时器的创建、开始、结束、删除步骤,步骤如下。
timer定时器的工作全流程:
- 反初始化定时器:调用uapi_timer_deinit();将timer进行反初始化,消除对后面timer初始化的影响。
- 初始化定时器:调用uapi_timer_init();将timer进行初始化。
- 适配定时器配置:调用uapi_timer_adapter();配置定时器索引、定时器中断号和中断优先级。
-
创建定时器:调用uapi_timer_create();创建一个高精度定时器,函数参数句柄为唯一定时器标 识。
-
开启定时器:调用uapi_timer_start();设置超时时间、超时回调函数、回调函数入参以及启动定 时器。
-
停止定时器:调用uapi_timer_stop();停止当前定时器计时。
- 删除定时器:调用uapi_timer_delete();删除当前定时器。
timer 模式
timer 支持以下工作模式:
| 模式 | 特点 | 适用场景 |
|---|---|---|
| 周期模式 | 定期触发中断 | 系统心跳、周期性任务调度 |
| 单次模式 | 触发一次中断后停止 | 延时、超时检测 |
| 自由运行模式 | 计数器模式 | 时间测量、性能分析 |
API 接口列表
本文档示例代码中使用的接口:
| 接口函数 | 说明 |
|---|---|
| uapi_timer_init | 初始化 Timer |
| uapi_timer_deinit | 去初始化 Timer |
| uapi_timer_adapter | 配置定时器参数 |
| uapi_timer_create | 创建定时器 |
| uapi_timer_start | 启动定时器 |
| uapi_timer_stop | 停止定时器 |
| uapi_timer_delete | 删除定时器 |
完整 API 列表
更多 Timer 接口请参考:Timer API 参考
快速跑通 timer_demo
配置说明
timer_demo 支持通过AT指令进行 timer 定时器的创建、开启、结束和删除功能。相应的AT指令如下:
AT指令参数说明 | 参数 | 默认值 | 说明 | |---|---|---| |timer_pority | 1 | 定时器中断优先级 |
| timer_index_no | 1 | 定时器索引 |
| start_time1 | 0 | timer1定时开始时间(ms) |
| end_time1 | 0 | timer1定时结束时间(ms) |
| delay_time1 | 1000 | timer1定时间隔时间(ms) |
| start_time2 | 0 | timer2定时开始时间(ms) |
| end_time2 | 0 | timer2定时结束时间(ms) |
| delay_time2 | 2000 | timer2定时间隔时间(ms) |
编译
完成一站式 CLI 环境配置后执行:
# 编译固件,编译生成的固件从 output/3322/fwpkgt 中获取 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
使用方式
- 烧录固件并启动设备
- 通过串口发送 AT 命令,格式如下:

预期结果

文件结构与代码走读
文件职责
| 文件 | 作用 |
|---|---|
| samples/native_samples/timer/CMakeLists.txt | 定义 timer_sample 组件及依赖。 |
| samples/native_samples/timer/timer_demo.h | 定义测试参数、范围约束和命令表。 |
| samples/native_samples/timer/timer_demo.c | 实现定时器创建、启动、回调、计时校验和释放。 |
| samples/native_samples/timer/README.md | 给出完整命令和预期日志。 |
核心数据与常量
| 名称 | 作用 | 开发注意事项 |
|---|---|---|
timer_info_t |
保存每个定时器的开始、结束和设定延时。 | 回调与业务线程共享数据时应考虑并发可见性。 |
timer_handle_t |
标识创建成功的定时器实例。 | 每个成功创建的句柄都要停止并删除。 |
TIMER_NUM |
Sample 同时创建的定时器数量。 | 数组容量、回调索引和等待条件必须保持一致。 |
TIMER_MS_2_US |
将毫秒与微秒参数进行换算。 | 调用接口前确认单位,避免把日志单位直接作为接口单位。 |
timer_task_args_t |
承载 AT 测试选择的索引和中断优先级。 | 自定义应用应由产品配置提供这些值,并在调用前校验范围。 |
核心业务流程
- 调用
uapi_timer_init(),配置定时器索引、中断号和优先级。 - 为每个业务定时器调用
uapi_timer_create(),记录开始时间并用uapi_timer_start()注册回调。 - 回调只记录结束时间、更新轻量状态或通知任务,避免在中断上下文执行阻塞操作。
- 业务任务收到完成条件后,依次停止、删除所有句柄,再调用
uapi_timer_deinit()。 - 任一步失败时只释放已经成功获取的资源,并避免等待一个未启动的定时器。
AT 命令仅用于传入索引和优先级并触发上述流程。下一节将向你展示 以app_run 为示例入口的实现过程。
基于 timer_demo 开发自己的应用
上面的demo是使用AT指令触发运行,HiDiTing还支持app_run方式触发应用在系统启动时自动运行,以下示例将以app_run的方式开发一个开发者自己的应用
- app_run(func) 是HiDiTing中应用层注册应用函数的宏,基于 GCC 编译器属性和自定义段区(section)自动注册来实现集中调用应用函数,系统启动时会自动遍历所有用 app_run 注册过的函数并执行,无需在 系统 main 函数里逐个调用函数。
代码清单
新建一个 timer 应用(以 my_timer_app 为例)通常只需要以下改动:
- 新建
my_timer_app.c源文件 - 新建
my_timer_app.h源文件 - 新建
CMakeLists.txt源文件 - 在
my_timer_demo.c实现timer的初始化,创建、开始操作 - 在
my_timer_demo.h中对void my_timer_demo(void)声明 - 在
CMakeLists.txt中添加源文件编译规则
my_timer_demo文件结构:
CMakeLists.txt 修改示例
# 在新建的 CMakeLists.txt 中添加应用的源文件
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/my_timer_demo.c
)
set(PUBLIC_HEADER
${CMAKE_CURRENT_SOURCE_DIR}
)
set(PRIVATE_HEADER
)
set(PUBLIC_DEFINES
MY_TIMER_DEMO_ENABLE
)
build_component()
关键代码片段
my_timer_app.c —— timer 示例
#include "timer.h"
#include "tcxo.h"
#include "app_init.h"
#include "common_def.h"
#define MY_TIMER_DELAY_MS 10
#define MY_TIMER_PRIO 2
static errcode_t my_timer_callback(uintptr_t data)
{
UNUSED(data);
osal_printk("timer timeout!\r\n");
return ERRCODE_SUCC;
}
void my_timer_demo(void)
{
osal_printk("my_timer_app start\n");
uint32_t g_timer_int_count = 0;
// step1:初始化 timer
uapi_timer_init();
uapi_timer_adapter(0, TIMER_1_IRQN, MY_TIMER_PRIO);
// step2:创建定时器
timer_handle_t timer_handle;
uapi_timer_create(0, &timer_handle);
// step3:启动定时器
uapi_timer_start(timer_handle, MY_TIMER_DELAY_MS * 1000, my_timer_callback, 0);
// step4:等待定时器结束
do {
osal_msleep(1000);
osal_printk("Main task running...\r\n");
g_timer_int_count++;
}while (g_timer_int_count < MY_TIMER_DELAY_MS);
// step5: 停止定时器
uapi_timer_stop(timer_handle);
// step6: 删除定时器
uapi_timer_delete(timer_handle);
// step7:反初始化 timer
uapi_timer_deinit();
}
app_run运行配置
app_run应用默认是关闭的,如需启用此应用,需用户手动在acore.prelds文件中添加 KEEP (*(SORT(.zinitcall.app_run*.init))) 具体参考示意图如下:

测试验证
新demo完成后,逐项验收:
- 设备启动后串口输出
my_timer_app start - 每隔1秒输出一次定时器超时信息
- 主任务每隔500ms输出一次运行信息
注意事项
时钟源注意事项:
- timer是基于外部32MHz晶体为系统提供高精度定时器的功能
- 高精度场景请使用高精度硬件定时器
优先级注意事项:
- 中断优先级过高可能影响系统稳定性
- 定时器回调函数应尽量简短
资源说明:
- timer 通常为硬件模块,无需额外资源分配
常见错误
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
undefined reference to 'uapi_timer_init' |
未链接 timer 驱动库 | 检查 CMakeLists.txt 中是否正确添加了源文件 |
TIMER_INDEX not defined |
未定义定时器索引 | 确保在代码中正确定义了定时器索引 |
undefined reference to 'uapi_at_cmd_table_register' |
未链接 AT 命令库 | 检查 CMakeLists.txt 中是否正确添加了 AT 相关头文件路径 |
编译报 at_ret_t 未定义 |
未包含 at.h 头文件 |
添加 #include "at.h" |
| 串口无输出 | AT 命令未注册 | 确认调用了 at_diting_timer_example_cmd_register() |
| 定时器不触发 | 中断优先级设置过高或未正确初始化 | 检查中断优先级和初始化代码 |