4.5.4 定时器 API
4.5.4 定时器 API
📚 本节导读
学习时长: 约 45 分钟
难度级别: ⭐⭐⭐☆☆
前置知识: 系统时钟概念、哈希桶/单链表定时器机制(4.5.2 / 4.5.3)、C 语言回调函数、位运算
定时器 API 是内核对外暴露的定时器使用接口。无论底层是哈希桶定时器还是单链表定时器,用户都是通过这一套统一的 API 来创建、启动、停止和查询定时器。本节作为定时器 API 使用手册,聚焦每个 API 的签名、参数、返回值、使用示例与跨实现的差异对比。
关于实现源码:定时器有两种实现——哈希桶(4.5.2)与单链表(4.5.3)。这两个实现各有
os_timer_create等同名 API 的独立源码。本节不再贴任何实现源码;各 API 的完整实现与分步详解请前往对应章节查阅:
- 哈希桶版实现 → 4.5.2 哈希桶定时器("五、哈希桶定时器 API 实现")
- 单链表版实现 → 4.5.3 单链表定时器("六、单链表定时器 API 实现")
前置阅读:本节频繁引用两个概念——
- 哈希桶定时器(
OS_USING_HASH_BUCKET_TIMER):只有软件定时器,回调在定时器任务中执行,见4.5.2。- 单链表定时器(
OS_USING_SINGLE_LIST_TIMER):分硬/软两种,见4.5.3。
🎯 学习目标
- 掌握所有定时器 API 的函数签名、参数与返回值
- 理解定时器标志的含义与组合方式(含硬/软定时器)
- 能够编写单次触发、周期性、静态/动态创建的定时器代码
- 明确各 API 在哈希桶与单链表两种实现下的差异,并能定位对应实现章节
一、定时器 API 概览
所有定时器 API 在 kernel/include/os_timer.h 中声明,在 OS_USING_KERNEL_TIMER 宏启用时可用。
来源: kernel/include/os_timer.h(接口声明,非实现)
#ifdef OS_USING_KERNEL_TIMER
#define OS_TIMER_FLAG_ONE_SHOT 0x0U /* Oneshot timer. */
#define OS_TIMER_FLAG_PERIODIC 0x1U /* Periodic timer. */
typedef struct dummy_timer os_timer_dummy_t;
typedef os_timer_dummy_t *os_timer_id;
#define OS_TIMER_DEFINE(name) \
OS_ALIGN(OS_ARCH_STACK_ALIGN_SIZE) \
os_timer_dummy_t name /* Here, actually, it is an array of os_timer_t structure size. \
The purpose is to serve as a timer control block for \
static create of timer. */API 分类一览表:
| 类别 | API | 功能 | 实现见 |
|---|---|---|---|
| 创建/销毁 | os_timer_create | 创建定时器(静态/动态) | 4.5.2 的 5.1 / 4.5.3 的 6.1 |
| 创建/销毁 | OS_TIMER_DEFINE | 静态定义定时器控制块 | 本节 4.2 |
| 创建/销毁 | os_timer_destroy | 销毁定时器 | 4.5.2 的 5.2 / 4.5.3 的 6.2 |
| 控制 | os_timer_start | 启动定时器 | 4.5.2 的 5.3 / 4.5.3 的 6.3 |
| 控制 | os_timer_stop | 停止定时器 | 4.5.2 的 5.4 / 4.5.3 的 6.4 |
| 控制 | os_timer_set_timeout_ticks | 设置超时 tick 数 | 4.5.2 的 5.5(两实现逐字相同) |
| 查询 | os_timer_get_timeout_ticks | 获取超时 tick 数 | 4.5.2 的 5.6(两实现逐字相同) |
| 查询 | os_timer_get_remain_ticks | 获取剩余 tick 数 | 4.5.2 的 5.7 / 4.5.3 的 6.9 |
| 查询 | os_timer_get_name | 获取定时器名称 | 两实现逐字相同 |
| 查询 | os_timer_is_active | 检查定时器是否活跃 | 两实现逐字相同 |
| 查询 | os_timer_is_periodic | 检查是否为周期模式 | 两实现逐字相同 |
| 查询 | os_timer_check_exist | 检查定时器是否存在 | 4.5.2 的 5.8 / 单链表版差异 |
| 模式 | os_timer_set_oneshot | 设为单次模式 | 两实现逐字相同 |
| 模式 | os_timer_set_periodic | 设为周期模式 | 两实现逐字相同 |
| 分类 | os_timer_is_soft | 检查是否为软件定时器(仅单链表) | 4.5.3 的 6.5 |
说明:本节的
os_timer_create等 API 是内核统一接口,其底层在4.5.2(哈希桶)与4.5.3(单链表)各有实现。用户只关心这套统一接口,无需关心底层差异;如需了解某个 API 在特定实现下的内部流程,可点击上方表格"实现见"列的链接。
二、定时器控制块与标志概述
本节只做接口层面的控制块字段与标志位说明,方便理解 API 参数。数据结构源码与机制详解见
4.5.2的 2.x /4.5.3的 2.x 节。
2.1 控制块关键字段
os_timer_t 是定时器控制块(完整结构见 4.5.2 的 2.1 节)。本节只说明用户最关心的字段:
| 字段 | 含义 | 操作 API |
|---|---|---|
timeout_func | 超时回调函数指针 | 创建时传入 function |
parameter | 传给回调的参数 | 创建时传入 parameter |
init_ticks | 初始超时 tick 数("总超时") | os_timer_set/get_timeout_ticks |
round_ticks | 当前剩余 tick 数("还剩多少") | os_timer_get_remain_ticks |
name | 定时器名称字符串 | os_timer_get_name |
active_node.flag | 状态标志位(周期/激活/动态/软硬等) | os_timer_set_oneshot 等 |
os_timer_t的内部字段是内核私有的,用户不应直接访问或修改,应通过本节的os_timer_*API 操作。标志位的完整位定义见4.5.2的 2.3 节。
2.2 定时器标志(接口层)
来源: kernel/include/os_timer.h
#define OS_TIMER_FLAG_ONE_SHOT 0x0U /* Oneshot timer. */
#define OS_TIMER_FLAG_PERIODIC 0x1U /* Periodic timer. */| 标志 | 值 | 含义 |
|---|---|---|
OS_TIMER_FLAG_ONE_SHOT | 0x0 | 单次触发:到期后自动停止 |
OS_TIMER_FLAG_PERIODIC | 0x1 | 周期触发:到期后自动重新启动 |
这两个标志在哈希桶与单链表定时器中通用。位 0(bit0)决定单次/周期:
flag & OS_TIMER_FLAG_PERIODIC非 0 为周期,为 0 为单次。
硬/软定时器标志(仅单链表定时器,详见 4.5.3 的 2.2 节):
| 标志 | 回调执行上下文 | 详解见 |
|---|---|---|
OS_TIMER_FLAG_HARD_TIMER(0x0) | tick ISR | 4.5.3 的 2.2 节 |
OS_TIMER_FLAG_SOFT_TIMER(0x4) | 定时器任务 | 4.5.3 的 2.2 节 |
注意:哈希桶定时器没有硬/软标志,回调统一在定时器任务中执行。硬/软标志只在
OS_USING_SINGLE_LIST_TIMER下有意义。
标志组合速查表:
| 组合 | 含义 |
|---|---|
OS_TIMER_FLAG_ONE_SHOT | 单次软件定时器(哈希桶)/ 单次硬定时器(单链表,默认) |
OS_TIMER_FLAG_PERIODIC | 周期软件定时器(哈希桶)/ 周期硬定时器(单链表,默认) |
OS_TIMER_FLAG_ONE_SHOT | OS_TIMER_FLAG_HARD_TIMER | 单次硬件定时器(单链表) |
OS_TIMER_FLAG_PERIODIC | OS_TIMER_FLAG_HARD_TIMER | 周期硬件定时器(单链表) |
OS_TIMER_FLAG_ONE_SHOT | OS_TIMER_FLAG_SOFT_TIMER | 单次软件定时器(单链表) |
OS_TIMER_FLAG_PERIODIC | OS_TIMER_FLAG_SOFT_TIMER | 周期软件定时器(单链表) |
易混淆点:
OS_TIMER_FLAG_ONE_SHOT(0x0)与OS_TIMER_FLAG_HARD_TIMER(0x0)数值相同。在单链表定时器中,若只配置了硬定时器,未指定软标志的定时器会被k_single_list_timer_check_flag强制转为硬定时器(见4.5.3);"单次"与"硬/软"是两个正交维度,不要混淆。
三、创建与销毁
3.1 os_timer_create —— 创建定时器
函数签名
来源: kernel/include/os_timer.h
extern os_timer_id os_timer_create(os_timer_dummy_t *timer_cb,
const char *name,
void (*function)(void *parameter),
void *parameter,
os_tick_t timeout,
uint8_t flag);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_cb | os_timer_dummy_t * | 定时器控制块内存。传 OS_NULL 时动态分配(需 OS_USING_HEAP);传 OS_TIMER_DEFINE 定义的静态控制块时使用静态内存 |
name | const char * | 定时器名称(最多 OS_NAME_MAX 字符) |
function | void (*)(void *) | 超时回调函数 |
parameter | void * | 传递给回调函数的参数 |
timeout | os_tick_t | 超时时间(单位 tick),常用 os_tick_from_ms() 由毫秒转换 |
flag | uint8_t | 定时器标志(见 2.2) |
| 返回值 | 含义 |
|---|---|
非 OS_NULL | 成功,返回定时器 ID |
OS_NULL | 失败(动态分配失败,或回调等参数非法) |
行为说明与跨实现差异
- 统一行为:
timer_cb为OS_NULL时动态创建(需堆),否则静态创建;静态创建会清除OS_TIMER_FLAG_DYNAMIC标志,动态创建会置上该标志。 - 中断限制:不能在中断上下文调用(实现会断言)。
- 哈希桶版:用自旋锁保护,静态创建会遍历全局链表
gs_os_timer_list查重(防止重复创建同一控制块)。 - 单链表版:调用
k_single_list_timer_check_flag校正默认硬/软标志,用关中断临界区保护,无静态查重。
| 差异点 | 哈希桶版 | 单链表版 |
|---|---|---|
| 内部初始化函数 | _k_timer_do_init | k_single_list_timer_do_init |
| 默认硬/软校正 | 无(只有软件定时器) | 调 k_single_list_timer_check_flag |
| 锁/临界区 | 自旋锁 gs_os_timer_list_lock | OS_KERNEL_ENTER/EXIT 关中断 |
| 静态查重 | 遍历全局链表查重 | 无显式查重 |
完整实现:哈希桶版见 4.5.2 的 5.1,单链表版见 4.5.3 的 6.1。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
/* 定时器回调函数 */
static void timer_callback(void *parameter)
{
os_kprintf("Timer fired! Param: %s\r\n", (char *)parameter);
}
void timer_create_demo(void)
{
os_timer_id timer;
/* 步骤1:动态创建定时器,2000ms 后触发回调 */
timer = os_timer_create(OS_NULL,
"my_timer",
timer_callback,
"hello",
os_tick_from_ms(2000),
OS_TIMER_FLAG_ONE_SHOT);
/* 步骤2:检查返回值,创建失败立即返回 */
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
/* 步骤3:启动定时器 */
os_timer_start(timer);
/* 步骤4:等待定时器触发后销毁 */
os_task_msleep(3000);
os_timer_destroy(timer);
}实际效果:程序创建单次定时器,2 秒后回调打印
Timer fired! Param: hello,随后定时器被销毁。
3.2 OS_TIMER_DEFINE —— 静态定义定时器控制块
宏定义
来源: kernel/include/os_timer.h
#define OS_TIMER_DEFINE(name) \
OS_ALIGN(OS_ARCH_STACK_ALIGN_SIZE) \
os_timer_dummy_t name /* Here, actually, it is an array of os_timer_t structure size. \
The purpose is to serve as a timer control block for \
static create of timer. */用法要点
- 在全局或静态作用域定义一个
os_timer_dummy_t类型的控制块(实际上按os_timer_t大小分配内存)。 - 配合
os_timer_create(&name, ...)使用,不依赖堆,适合不使用OS_USING_HEAP的场景。 - 静态控制块的生命周期由用户管理,
os_timer_destroy不会释放其内存。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
/* 静态定义定时器控制块(全局变量) */
OS_TIMER_DEFINE(static_timer_cb);
static void static_timer_callback(void *parameter)
{
os_kprintf("Static timer fired!\r\n");
}
void static_timer_demo(void)
{
os_timer_id timer;
/* 使用静态控制块创建定时器,1000ms 触发一次 */
timer = os_timer_create(&static_timer_cb,
"static_tmr",
static_timer_callback,
OS_NULL,
os_tick_from_ms(1000),
OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create static timer\r\n");
return;
}
os_timer_start(timer);
os_task_msleep(2000);
/* 销毁定时器(静态控制块内存不会被释放) */
os_timer_destroy(timer);
}实际效果:程序用静态控制块创建单次定时器,1 秒后回调打印
Static timer fired!;os_timer_destroy只注销定时器,不释放static_timer_cb这块内存(因其由用户管理)。
3.3 os_timer_destroy —— 销毁定时器
函数签名
来源: kernel/include/os_timer.h
extern os_err_t os_timer_destroy(os_timer_id timer_id);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 要销毁的定时器 ID |
| 返回值 | 含义 |
|---|---|
OS_SUCCESS | 销毁成功 |
行为说明与跨实现差异
- 统一行为:销毁定时器会将其从管理链表/排序链表摘除、停掉活跃计时、清除"已初始化"标志;动态创建的会释放堆内存,静态创建的不释放。
- 中断限制:不能在中断上下文调用(实现会断言)。
- 哈希桶版:用
_k_timer_remove摘链并停计时,额外断言os_is_irq_disabled/os_is_schedule_locked。 - 单链表版:用
OS_TIMER_FLAG_DO_TIMEOUT判断"回调中自销毁"场景,保证在回调中销毁自己是安全的;动态标志位为0x10。
| 差异点 | 哈希桶版 | 单链表版 |
|---|---|---|
| 移除动作 | _k_timer_remove(摘管理链表 → 停活跃 → 清 INITED) | 判断 DO_TIMEOUT:回调中只清标志摘 timeout 列表,否则 k_single_list_timer_deactivate |
| 中断断言 | 额外断言 os_is_irq_disabled、os_is_schedule_locked | 仅断言 os_is_irq_active |
| 动态标志位 | OS_TIMER_FLAG_DYNAMIC = 0x4 | OS_TIMER_FLAG_DYNAMIC = 0x10 |
完整实现:哈希桶版见 4.5.2 的 5.2,单链表版见 4.5.3 的 6.2。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void destroy_demo_cb(void *parameter)
{
os_kprintf("Callback fired, will destroy timer\r\n");
}
void timer_destroy_demo(void)
{
os_timer_id timer;
os_err_t ret;
timer = os_timer_create(OS_NULL, "destroy_tmr", destroy_demo_cb, OS_NULL,
os_tick_from_ms(1000), OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
os_timer_start(timer);
/* 等待回调触发后销毁 */
os_task_msleep(2000);
ret = os_timer_destroy(timer);
if (ret != OS_SUCCESS)
{
os_kprintf("Destroy failed\r\n");
return;
}
os_kprintf("Timer destroyed\r\n");
}实际效果:定时器 1 秒后回调打印
Callback fired...,随后任务睡到 2 秒时销毁定时器,打印Timer destroyed。
四、启动与停止
4.1 os_timer_start —— 启动定时器
函数签名
来源: kernel/include/os_timer.h
extern os_err_t os_timer_start(os_timer_id timer_id);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 要启动的定时器 ID |
| 返回值 | 含义 |
|---|---|
OS_SUCCESS | 启动成功 |
行为说明与跨实现差异
- 统一行为:"先停后启"——先停掉旧活跃状态,再按
init_ticks从初始超时重新计时。重复os_timer_start会重新计时。 - 为什么"先停后启":若不先停旧的活跃状态,重复启动会重复挂入活跃桶/排序链表,导致"一个定时器多个计时节点"的脏状态。
- 哈希桶版:
_k_timer_deactivate+_k_timer_activate(后者计算桶索引、挂入活跃桶)。 - 单链表版:
k_single_list_timer_deactivate+k_single_list_timer_activate(后者插入排序链表)。
完整实现:哈希桶版见 4.5.2 的 5.3,单链表版见 4.5.3 的 6.3。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void led_blink_callback(void *parameter)
{
os_kprintf("LED blink\r\n");
}
void timer_start_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "led_tmr", led_blink_callback, OS_NULL,
os_tick_from_ms(500), OS_TIMER_FLAG_PERIODIC);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
/* 启动周期定时器,每 500ms 触发一次 */
if (os_timer_start(timer) == OS_SUCCESS)
{
os_kprintf("Timer started, blinks every 500ms\r\n");
}
os_task_msleep(3000);
os_timer_destroy(timer);
}4.2 os_timer_stop —— 停止定时器
函数签名
来源: kernel/include/os_timer.h
extern os_err_t os_timer_stop(os_timer_id timer_id);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 要停止的定时器 ID |
| 返回值 | 含义 |
|---|---|
OS_SUCCESS | 停止成功(定时器原本在运行) |
OS_FAILURE | 定时器未在运行,无需停止 |
行为说明与跨实现差异
- 统一行为:若定时器正在运行(
flag & ACTIVATED非 0)则停止并返回OS_SUCCESS;若未在运行则返回OS_FAILURE。 - 为什么"未运行返回
OS_FAILURE":让调用方能区分"我确实停掉了一个正在跑的定时器"(OS_SUCCESS)与"它本来就没在跑"(OS_FAILURE)。因此应检查返回值。 - 哈希桶版:激活时
_k_timer_deactivate停止并摘除活跃桶节点。 - 单链表版:激活时
k_single_list_timer_deactivate停止并摘除排序链表节点。
完整实现:哈希桶版见 4.5.2 的 5.4,单链表版见 4.5.3 的 6.4。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void stop_demo_cb(void *parameter)
{
os_kprintf("This should NOT print if stopped\r\n");
}
void timer_stop_demo(void)
{
os_timer_id timer;
os_err_t ret;
timer = os_timer_create(OS_NULL, "stop_tmr", stop_demo_cb, OS_NULL,
os_tick_from_ms(1000), OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
os_timer_start(timer);
/* 500ms 后停止,定时器应不再触发 */
os_task_msleep(500);
ret = os_timer_stop(timer);
if (ret == OS_SUCCESS)
{
os_kprintf("Timer stopped in time\r\n");
}
else
{
os_kprintf("Timer was not running\r\n");
}
os_task_msleep(1500); /* 等待,验证回调不会触发 */
os_timer_destroy(timer);
}实际效果:定时器启动 500ms 后即被停止,返回值
OS_SUCCESS,后续 1.5 秒内不会打印This should NOT print。
五、查询函数
以下查询函数在哈希桶与单链表两实现下源码结构基本一致,仅在剩余时间计算等个别处有实现差异。统一签名、参数、返回值与示例在本节给出;实现见对应章节。
5.1 os_timer_set_timeout_ticks —— 设置超时 tick 数
函数签名
来源: kernel/include/os_timer.h
extern os_err_t os_timer_set_timeout_ticks(os_timer_id timer_id, os_tick_t timeout);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 定时器 ID |
timeout | os_tick_t | 新的超时 tick 数 |
| 返回值 | 含义 |
|---|---|
OS_SUCCESS | 设置成功 |
行为说明
- 两实现逐字相同(实现在
4.5.2的 5.5 节给出)。 - 只把
init_ticks改成timeout,不修改round_ticks,也不改变运行状态。 - 注意:此 API 只改"下次启动用的超时",对当前正在运行的定时器计时无影响。重新
os_timer_start(先停后启)后才按新值计时。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void set_timeout_cb(void *parameter)
{
os_kprintf("Timer fired\r\n");
}
void set_timeout_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "set_tmr", set_timeout_cb, OS_NULL,
os_tick_from_ms(1000), OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
/* 把超时改成 2 秒,再启动 */
if (os_timer_set_timeout_ticks(timer, os_tick_from_ms(2000)) == OS_SUCCESS)
{
os_kprintf("Timeout set to 2000ms\r\n");
}
os_timer_start(timer);
os_task_msleep(3000);
os_timer_destroy(timer);
}实际效果:定时器按 2 秒(而非创建时的 1 秒)触发回调。
5.2 os_timer_get_timeout_ticks —— 获取超时 tick 数
函数签名
来源: kernel/include/os_timer.h
extern os_tick_t os_timer_get_timeout_ticks(os_timer_id timer_id);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 定时器 ID |
| 返回值 | 含义 |
|---|---|
os_tick_t | 初始超时 tick 数(init_ticks) |
行为说明
- 两实现逐字相同(实现在
4.5.2的 5.6 节给出)。 - 返回的是初始超时(
init_ticks,"总超时"),而非剩余时间。
易混淆:
get_timeout_ticks(初始值,init_ticks)≠get_remain_ticks(剩余值)。前者是"创建时设定的超时",后者是"当前还差多少 tick"。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void get_timeout_cb(void *parameter)
{
os_kprintf("Timer fired\r\n");
}
void get_timeout_demo(void)
{
os_timer_id timer;
os_tick_t ticks;
timer = os_timer_create(OS_NULL, "get_tmr", get_timeout_cb, OS_NULL,
os_tick_from_ms(1000), OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
ticks = os_timer_get_timeout_ticks(timer);
os_kprintf("Timeout: %lu ticks\r\n", ticks);
os_timer_destroy(timer);
}实际效果:打印
Timeout: <1 秒对应的 tick 数> ticks(具体数值取决于os_get_ticks_per_second())。
5.3 os_timer_get_remain_ticks —— 获取剩余 tick 数
函数签名
来源: kernel/include/os_timer.h
extern os_tick_t os_timer_get_remain_ticks(os_timer_id timer_id);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 定时器 ID |
| 返回值 | 含义 |
|---|---|
os_tick_t | 当前剩余 tick 数 |
行为说明与跨实现差异
- 统一行为:返回定时器的绝对剩余 tick 数;若定时器未激活(未 start 或已到期),返回 0。
- 实现差异(这是本节唯一在剩余计算上有实现差别的查询函数):
- 哈希桶版:调
_k_timer_calc_remain_ticks,用桶索引 + 补偿计算(见 4.5.2 的 5.7)。 - 单链表版:调
k_single_list_timer_calc_remain_ticks,按排序链表顺序累加差值(见 4.5.3 的 6.9)。
- 哈希桶版:调
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void remain_demo_cb(void *parameter)
{
os_kprintf("Timer fired\r\n");
}
void remain_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "remain_tmr", remain_demo_cb, OS_NULL,
os_tick_from_ms(2000), OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
os_timer_start(timer);
/* 1000ms 后查询剩余时间(应约为 1000ms 对应的 tick 数) */
os_task_msleep(1000);
os_kprintf("Remain ticks: %lu\r\n", os_timer_get_remain_ticks(timer));
os_task_msleep(2000);
os_timer_destroy(timer);
}实际效果:启动 1 秒后查询,打印剩余 tick 数(约为总超时的一半);定时器在 2 秒时触发回调。
5.4 os_timer_get_name —— 获取定时器名称
函数签名
来源: kernel/include/os_timer.h
extern const char *os_timer_get_name(os_timer_id timer_id);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 定时器 ID |
| 返回值 | 含义 |
|---|---|
const char * | 定时器名称字符串指针 |
行为说明
- 两实现逐字相同。
- 直接返回
timer->name数组起始地址,无临界区保护(只读字符串,任务上下文读取无需锁)。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void name_demo_cb(void *parameter)
{
os_kprintf("Timer fired\r\n");
}
void name_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "my_heartbeat", name_demo_cb, OS_NULL,
os_tick_from_ms(1000), OS_TIMER_FLAG_PERIODIC);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
os_kprintf("Timer name: %s\r\n", os_timer_get_name(timer));
os_timer_destroy(timer);
}实际效果:打印
Timer name: my_heartbeat。
5.5 os_timer_is_active —— 检查定时器是否活跃
函数签名
来源: kernel/include/os_timer.h
extern os_bool_t os_timer_is_active(os_timer_id timer_id);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 定时器 ID |
| 返回值 | 含义 |
|---|---|
os_bool_t | OS_TRUE = 正在运行;OS_FALSE = 未运行 |
行为说明
- 两实现逐字相同。
- 返回
flag & OS_TIMER_FLAG_ACTIVATED是否非 0。ACTIVATED表示该定时器已os_timer_start且尚未到期(或未停止)。单次到期后、os_timer_stop后均为OS_FALSE。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void active_demo_cb(void *parameter)
{
os_kprintf("Timer fired\r\n");
}
void active_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "active_tmr", active_demo_cb, OS_NULL,
os_tick_from_ms(1000), OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
os_timer_start(timer);
os_kprintf("Active after start: %d\r\n", os_timer_is_active(timer)); /* 打印 1 */
os_task_msleep(1500);
os_kprintf("Active after expire: %d\r\n", os_timer_is_active(timer)); /* 打印 0 */
os_timer_destroy(timer);
}实际效果:启动后打印
Active after start: 1;单次定时器到期后打印Active after expire: 0。
5.6 os_timer_is_periodic —— 检查是否为周期模式
函数签名
来源: kernel/include/os_timer.h
extern os_bool_t os_timer_is_periodic(os_timer_id timer_id);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 定时器 ID |
| 返回值 | 含义 |
|---|---|
os_bool_t | OS_TRUE = 周期模式;OS_FALSE = 单次模式 |
行为说明
- 两实现逐字相同。
- 返回
flag & OS_TIMER_FLAG_PERIODIC是否非 0。
易混淆:
os_timer_is_periodic(检查模式)与os_timer_is_active(检查是否在运行)是两个正交维度。一个周期模式(is_periodic= 真)的定时器可以处于未激活(is_active= 假)状态,例如创建后尚未start。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void periodic_mode_cb(void *parameter)
{
os_kprintf("Timer fired\r\n");
}
void periodic_mode_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "periodic_tmr", periodic_mode_cb, OS_NULL,
os_tick_from_ms(500), OS_TIMER_FLAG_PERIODIC);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
os_kprintf("Is periodic: %d\r\n", os_timer_is_periodic(timer)); /* 打印 1 */
os_kprintf("Is active before start: %d\r\n", os_timer_is_active(timer)); /* 打印 0 */
os_timer_destroy(timer);
}实际效果:创建为周期模式的定时器,
is_periodic打印 1,is_active在未 start 时打印 0,体现"模式"与"运行状态"正交。
5.7 os_timer_check_exist —— 检查定时器是否存在
函数签名
来源: kernel/include/os_timer.h
extern os_bool_t os_timer_check_exist(os_timer_id timer_id);参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 定时器 ID |
| 返回值 | 含义 |
|---|---|
os_bool_t | OS_TRUE = 定时器已初始化存在;OS_FALSE = 不存在 |
行为说明与跨实现差异
- 统一行为:判断该
timer_id是否是一个已初始化的有效定时器。 - 注意:
os_timer_check_exist是唯一不做INITED断言的查询函数,可安全用于"判断一个 ID 是否有效",访问定时器前调用它可避免空指针/野指针风险。 - 实现差异:
- 哈希桶版:遍历全局管理链表
gs_os_timer_list查找(见 4.5.2 的 5.8)。 - 单链表版:直接检查
flag & INITED位(见kernel/source/os_timer_slist.c),语义一致。
- 哈希桶版:遍历全局管理链表
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void exist_demo_cb(void *parameter)
{
os_kprintf("Timer fired\r\n");
}
void exist_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "exist_tmr", exist_demo_cb, OS_NULL,
os_tick_from_ms(1000), OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
os_kprintf("Exist after create: %d\r\n", os_timer_check_exist(timer)); /* 打印 1 */
os_timer_destroy(timer);
os_kprintf("Exist after destroy: %d\r\n", os_timer_check_exist(timer)); /* 打印 0 */
}实际效果:创建后
os_timer_check_exist打印 1;销毁后打印 0。可用于在访问定时器前安全地判断其有效性。
5.8 模式切换:os_timer_set_oneshot / os_timer_set_periodic
函数签名
来源: kernel/include/os_timer.h
extern os_err_t os_timer_set_oneshot(os_timer_id timer_id);
extern os_err_t os_timer_set_periodic(os_timer_id timer_id);参数/返回值
| API | 参数 | 返回值 |
|---|---|---|
os_timer_set_oneshot | timer_id | OS_SUCCESS:清 OS_TIMER_FLAG_PERIODIC,设为单次模式 |
os_timer_set_periodic | timer_id | OS_SUCCESS:置 OS_TIMER_FLAG_PERIODIC,设为周期模式 |
行为说明
- 两实现逐字相同。
os_timer_set_oneshot:flag &= ~OS_TIMER_FLAG_PERIODIC,即flag & 0xFE,清除 bit0。os_timer_set_periodic:flag |= OS_TIMER_FLAG_PERIODIC,即flag | 0x01,置位 bit0。
注意:切换模式不影响当前运行状态,下次到期后按新模式处理。若在单次定时器已启动后调
set_periodic,它本次仍按单次触发,到期后(若未销毁)才按周期重新计时。因此通常在启动前设置好模式即可。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void mode_demo_cb(void *parameter)
{
os_kprintf("Timer fired\r\n");
}
void mode_switch_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "mode_tmr", mode_demo_cb, OS_NULL,
os_tick_from_ms(1000), OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
/* 启动前把单次改为周期模式 */
if (os_timer_set_periodic(timer) == OS_SUCCESS)
{
os_kprintf("Switched to periodic\r\n");
}
os_kprintf("Is periodic now: %d\r\n", os_timer_is_periodic(timer)); /* 打印 1 */
os_timer_start(timer);
os_task_msleep(2500);
os_timer_destroy(timer);
}实际效果:单次创建的定时器在启动前被切为周期模式,
is_periodic打印 1;启动后每 1 秒触发一次。
5.9 os_timer_is_soft —— 检查是否为软件定时器(仅单链表)
函数签名
来源: kernel/include/os_timer.h
/* Hash timers do not have hardware timers, only software timers */
#ifdef OS_USING_SINGLE_LIST_TIMER
extern os_bool_t os_timer_is_soft(os_timer_id timer_id);
#endif /* end of OS_USING_SINGLE_LIST_TIMER */参数/返回值
| 参数 | 类型 | 说明 |
|---|---|---|
timer_id | os_timer_id | 定时器 ID |
| 返回值 | 含义 |
|---|---|
os_bool_t | OS_TRUE = 软件定时器;OS_FALSE = 硬件定时器 |
行为说明
- 仅单链表定时器有,实现在 4.5.3 的 6.5。
- 返回
flag & OS_TIMER_FLAG_TASK_SCHED(即0x04)是否非 0:非 0 → 软件定时器(OS_TRUE);0 → 硬件定时器(OS_FALSE)。 - 哈希桶定时器只有软件定时器,无此区分(源码注释:"Hash timers do not have hardware timers")。
使用示例
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
/* 该示例需在 OS_USING_SINGLE_LIST_TIMER 且同时配置了硬/软定时器的环境下编译 */
static void soft_demo_cb(void *parameter)
{
os_kprintf("Timer fired\r\n");
}
void is_soft_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "soft_tmr", soft_demo_cb, OS_NULL,
os_tick_from_ms(1000),
OS_TIMER_FLAG_ONE_SHOT | OS_TIMER_FLAG_SOFT_TIMER);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
os_kprintf("Is soft timer: %d\r\n", os_timer_is_soft(timer)); /* 打印 1 */
os_timer_destroy(timer);
}实际效果:用
OS_TIMER_FLAG_SOFT_TIMER创建的定时器,os_timer_is_soft打印 1(软件定时器,回调在定时器任务中执行)。
六、综合使用示例
6.1 停止并重启定时器
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static void restartable_timer_callback(void *parameter)
{
os_kprintf("Timer fired!\r\n");
}
void restart_demo(void)
{
os_timer_id timer;
timer = os_timer_create(OS_NULL, "restart_tmr",
restartable_timer_callback, OS_NULL,
os_tick_from_ms(1000),
OS_TIMER_FLAG_ONE_SHOT);
if (timer == OS_NULL)
{
os_kprintf("Failed to create timer\r\n");
return;
}
/* 启动定时器,1 秒后到期 */
os_timer_start(timer);
os_kprintf("Timer started, will fire in 1000ms\r\n");
/* 500ms 时停止定时器 */
os_task_msleep(500);
if (os_timer_is_active(timer))
{
if (os_timer_stop(timer) == OS_SUCCESS)
{
os_kprintf("Timer stopped before firing\r\n");
os_kprintf("Remaining ticks: %lu\r\n", os_timer_get_remain_ticks(timer));
}
}
/* 重新启动定时器 */
os_timer_start(timer);
os_kprintf("Timer restarted, will fire in 1000ms\r\n");
os_task_msleep(2000);
os_timer_destroy(timer);
}实际效果:定时器启动 500ms 后被停止(剩余约 500ms),再重启后重新从 1000ms 计时。
6.2 周期定时器自动停止
#include <oneos_config.h>
#include <os_timer.h>
#include <os_task.h>
#include <os_clock.h>
static uint32_t periodic_count = 0;
static os_timer_id g_periodic_timer = OS_NULL; /* 供回调访问定时器 ID */
static void periodic_timer_callback(void *parameter)
{
periodic_count++;
os_kprintf("Periodic timer fired! Count: %lu\r\n", periodic_count);
if (periodic_count >= 10)
{
/* 第 10 次后停止定时器(通过全局变量引用定时器 ID) */
if (os_timer_stop(g_periodic_timer) == OS_SUCCESS)
{
os_kprintf("Periodic timer stopped after 10 times\r\n");
}
}
}
void periodic_timer_demo(void)
{
os_timer_id timer;
/* 创建周期定时器,每 500ms 触发一次 */
timer = os_timer_create(OS_NULL,
"periodic_tmr",
periodic_timer_callback,
OS_NULL,
os_tick_from_ms(500),
OS_TIMER_FLAG_PERIODIC);
if (timer == OS_NULL)
{
os_kprintf("Failed to create periodic timer\r\n");
return;
}
g_periodic_timer = timer;
os_timer_start(timer);
os_kprintf("Periodic timer started, fires every 500ms\r\n");
/* 等待定时器触发 10 次并自停 */
os_task_msleep(6000);
g_periodic_timer = OS_NULL;
os_timer_destroy(timer);
}实际效果:定时器每 500ms 回调一次,累计 10 次后(约 5 秒)回调内调用
os_timer_stop停止自己。
提示:若要在回调中引用定时器本身,因为
os_timer_create返回的timer在回调被调用前才存在,无法在创建时作为parameter自引用。常用解法是用一个全局变量保存timer供回调访问(如上);若parameter本就承载业务数据,也不要将其强转成定时器 ID,否则会造成空指针 bug。
七、使用注意事项
| 注意事项 | 说明 |
|---|---|
| 返回值检查 | 始终检查 os_timer_create 是否返回 OS_NULL,创建失败立即返回 |
| 回调限制 | 硬件定时器回调在 ISR 中执行(见 4.5.3),绝不能调用阻塞 API |
| 销毁前停止 | 建议销毁前先 os_timer_stop(回调中自销毁除外,源码已安全处理) |
| tick 转换 | 用 os_tick_from_ms() 将毫秒转 tick,避免硬编码 tick 值(受 os_get_ticks_per_second() 影响) |
| 静态/动态 | 静态控制块生命周期由用户管理,os_timer_destroy 不释放其内存;动态创建需 OS_USING_HEAP |
| 中断限制 | 创建/销毁不能在中断上下文调用(实现会断言) |
timeout 为 0 | 会被当作 1 tick 处理(实现 init_ticks = (0 == timeout) ? 1 : timeout) |
set_timeout_ticks 生效时机 | 只改 init_ticks,当前运行计时不受影响,重启后才按新值 |
is_periodic vs is_active | 前者查模式,后者查是否在运行,两个正交维度 |
check_exist 的用法 | 唯一不做 INITED 断言的查询函数,可在访问前安全判断 ID 有效性 |
| 实现源码位置 | 需阅读实现细节时,哈希桶版看 4.5.2、单链表版看 4.5.3 |
📝 本节小结
核心要点回顾
| 要点 | 说明 |
|---|---|
| 统一接口 | 无论哈希桶还是单链表,用户都通过 os_timer_* 系列 API 操作定时器 |
| 创建方式 | os_timer_create:传 OS_NULL 动态创建(需堆)、传 OS_TIMER_DEFINE 静态创建 |
| 标志位 | OS_TIMER_FLAG_ONE_SHOT/PERIODIC 通用;硬/软标志仅单链表(见 4.5.3) |
| start 先停后启 | 重复 os_timer_start 从初始超时重新计时 |
| stop 返回值 | OS_SUCCESS = 停止了在运行的定时器;OS_FAILURE = 本就没在运行 |
| 查询差异 | get_timeout_ticks 是初始值(init_ticks),get_remain_ticks 是剩余值(两实现计算不同) |
| 模式与运行正交 | is_periodic(查模式)≠ is_active(查是否在运行) |
os_timer_is_soft | 仅单链表有,哈希桶无硬件定时器 |
| 实现下沉 | 各 API 的实现源码已下沉至 4.5.2(哈希桶版)与 4.5.3(单链表版) |
关键易错点速查
| 易错点 | 正确做法 |
|---|---|
不检查 os_timer_create 返回值 | 返回 OS_NULL 说明创建失败,应检查并处理 |
| 硬定时器回调里调用阻塞 API | 硬定时器回调在 ISR 中,绝不能阻塞 |
| 混淆"初始超时"与"剩余时间" | get_timeout_ticks 是初始值,get_remain_ticks 是剩余值 |
| 未启用堆就用动态创建 | 动态创建需 OS_USING_HEAP;否则用 OS_TIMER_DEFINE 静态创建 |
| 在中断里创建/销毁定时器 | 创建/销毁断言禁止中断上下文调用 |
把 os_timer_is_soft 用于哈希桶 | 该 API 仅单链表定时器有,哈希桶无此概念 |
以为 set_timeout_ticks 立即生效 | 只改 init_ticks,重启(os_timer_start)后才按新值计时 |
直接访问 active_node.flag 等内部字段 | 应通过 os_timer_* API 操作,内部字段为内核私有 |
| 在 4.5.4 里找实现源码 | 实现源码已移至 4.5.2 / 4.5.3,本节只保留接口说明 |
下一步
- 4.6 错误处理机制:了解内核错误码与安全机制,正确处理定时器等 API 的返回值与异常。