xt-sdk 文档 v1.0.3
xt-sdk 嵌入式 SDK API 参考
载入中...
搜索中...
未找到
xt_timer - 软件定时器

版本:0.1 | 日期:2025-07-03 | 路径: components/xt_task/xt_timer.h


一、概述

一次性延时定时器,到期后在 xt_timer_handler 中触发回调。单线程环境下工作。采用 数组池 + ID 索引 方案,通过 UID 递增和 Magic 校验防止槽位复用导致的误操作。

1.1 设计原则

  • 一次性定时器 :到期触发后自动清除,非周期定时器
  • 数组池管理 :静态数组分配,无需动态内存
  • UID 保护 :ID 编码 (uid << 8) | slot ,每次分配 uid 递增,防止误操作被复用的槽位
  • Magic 校验 :每个槽位有 magic 哨兵值,检测内存踩踏

1.2 依赖

依赖 用途
xtiny.h 基础类型和宏
cmsis_os2.h(可选) OS 扩展( XT_TASK_ENABLE_OS 时)

二、核心概念

2.1 状态机

IDLE ──start()──▶ ARMED ──到期──▶ FIRING ──cb返回──▶ IDLE
▲ │ │
│ │ stop() │ stop()(回调中)
└──────────────────┘ │
└──────────────────────────────────────┘
  • IDLE :空闲,可被分配
  • ARMED :已启动,等待超时
  • FIRING :超时到期,正在执行回调(或刚执行完尚未清理)

FIRING 状态的核心作用:回调中 stop 自己时,handler 停下后检查 state != FIRING 或 uid 不匹配 ,不会重复清理已停止的定时器或错误清除被复用的槽位。

2.2 定时器 ID 编码

ID 编码为 (uid << 8) | slot :

  • XT_TIMER_MAKE_ID(uid, slot) — 编码
  • XT_TIMER_ID_TO_SLOT(timer_id) — 提取槽位(低 8 位)
  • XT_TIMER_ID_TO_UID(timer_id) — 提取 UID(高位)

UID 从 1 开始递增,跳过 0,回绕后也跳回 1。停止定时器时校验 uid 匹配,防止误删被复用的槽位。

2.3 Magic 校验

每个槽位有 magic 字段( XT_TIMER_MAGIC = 0x584D544DU ),在 setup 时设置,之后永不改变。所有操作前校验 magic,用于检测内存踩踏。若 magic 损坏的槽位状态为 IDLE, start 会跳过它继续查找其他可用槽位。


三、API 参考

以下为函数签名大纲,完整的参数说明、返回值、注意事项请查看 xt_timer(软件定时器) 。

3.1 生命周期

函数签名 说明
void xt_timer_setup(void) 初始化定时器模块,清零槽位并写入 magic

3.2 定时器操作

函数签名 说明
uint32_t xt_timer_start(xt_timer_cb_t timer_cb, void *user_data, uint32_t timeout_ms) 启动一次性定时器,返回 ID(INVALID 表示失败)
void xt_timer_stop_no_safe(uint32_t timer_id) 停止定时器(不修改传入的变量)
uint32_t xt_timer_remain(uint32_t timeout_tick) 计算剩余 tick 数(0 表示已到期)
uint32_t xt_timer_handler(void) 主循环处理,返回下次需等待的最小 tick 数

xt_timer_stop(timer_id) 是宏,内部临时变量保证参数仅求值一次,停止后置 timer_id 为 XT_TIMER_INVALID_ID 。参数必须是左值(变量)。


四、handler 返回值

返回 min(定时器下次超时, task 下次超时) 。主循环可将其用作延时参数:

void main_loop(void) {
while (1) {
uint32_t delay = xt_timer_handler();
if (delay > 0) {
osDelay(delay);
}
}
}
uint32_t xt_timer_handler(void)
定时器主循环处理函数

五、已知行为与限制

行为 说明
一次性 触发后自动清除,非周期定时器。需要周期触发请在回调中重新 start
timeout 上限 最大 INT32_MAX ms(约 24.8 天)
回调中 start timeout=0 新定时器可能在 同一轮 handler 中被触发(确定性行为)
回调中 stop 自己 安全,handler 不会重复清除
回调中 stop 后 start 同槽位 安全,handler 的 uid 检查防止误清除新定时器
未调用 setup 所有 magic 检查失败,start 返回 INVALID
槽满 start 返回 INVALID
xt_timer_stop 参数 必须是左值(变量),不能是函数返回值
定时器 ID 调用方需保存返回的 ID,用于后续 stop

六、编译配置

宏 默认值 说明
XT_TIMER_NUM 10 定时器槽位数量(最大 256)
XT_TIMER_ID_SLOT_BITS 8 槽位在 ID 中的位宽
XT_TIMER_MAGIC 0x584D544DU 内存踩踏检测哨兵值

七、常见模式

7.1 基本用法

uint32_t g_timer_id = 0;
void on_timeout(void *user_data) {
printf("定时器到期,数据: %p\n", user_data);
}
void app_init(void) {
}
void start_timer(void) {
g_timer_id = xt_timer_start(on_timeout, (void *)0xCAFE, 1000);
if (g_timer_id == XT_TIMER_INVALID_ID) {
// 处理失败
}
}
void stop_timer(void) {
xt_timer_stop(g_timer_id); // g_timer_id 被置为 INVALID
}
void xt_timer_setup(void)
初始化软件定时器模块
#define xt_timer_stop(timer_id)
uint32_t xt_timer_start(xt_timer_cb_t timer_cb, void *user_data, uint32_t timeout_ms)
启动一个软件定时器
#define XT_TIMER_INVALID_ID

7.2 主循环

void main_loop(void) {
while (1) {
uint32_t delay = xt_timer_handler();
osDelay(delay == UINT32_MAX ? 100 : delay);
}
}
xt_err_t xt_event_handler(void)
处理事件队列中的所有事件

7.3 回调中操作定时器

void cb_restart(void *user_data) {
xt_timer_stop(g_timer_id); // 停止自己
g_timer_id = xt_timer_start(cb_restart, NULL, 500); // 启动新定时器
// handler 回来后 uid 不匹配,不会误清除新定时器
}

八、测试

测试套件位于 tests/xt_timer/ :

cd tests/xt_timer
xt --target windows/simulator fullclean build
xt --target windows/simulator run