北屋教程网

专注编程知识分享,从入门到精通的编程学习平台

嵌入式定时器优雅解法:用软件定时器 soft_timer 提升你的代码质量

在嵌入式开发中,“定时”几乎无处不在——LED 闪烁、任务轮询、事件触发、超时重试、UI动画、通信心跳……每一个场景都在向你提出一个问题:你如何高效地管理多个异步时间事件?

STM32 的硬件定时器固然强大,但数量有限,且每次使用都要配置寄存器、时钟源、回调中断,工程复杂度指数级增长。有没有一种更轻量、灵活、高可复用的解决方案?答案就是:软件定时器(Soft Timer)

今天我们就来解析一个极具工程价值的开源项目:
https://gitee.com/stanley_shen/soft_timer
,看它如何帮助开发者轻松实现多定时任务调度。

什么是软件定时器?

软件定时器不是硬件资源,而是一种基于统一时基进行时间管理的软件策略,通常由系统时钟节拍(如 SysTick 每 1ms 中断一次)驱动,维护一个定时器链表或数组,按需触发用户定义的回调函数。

它最大的优势就是:用一个定时器,实现多个逻辑上的“定时任务”

soft_timer 的设计

soft_timer 项目的核心是极简、清晰、可移植,适合所有裸机或 RTOS 环境下的 MCU 项目。它通过以下模块组织完成整个定时器生命周期管理:

核心数据结构(soft_timer_t)

typedef struct soft_timer {
    uint32_t timeout;                   // 定时超时时间
    uint32_t counter;                   // 当前计数值
    void (*callback)(void*);            // 到时执行的回调函数
    void* user_data;                    // 回调函数参数
    bool repeat;                        // 是否为周期定时
    struct soft_timer* next;            // 链表指针
    bool active;                        // 是否处于运行状态
} soft_timer_t;

每个软件定时器都是一个结构体实例,包含:

  • timeout:定时时间(单位一般为 ms)
  • counter:当前计数值
  • callback:时间到后执行的函数
  • user_data:传入回调的参数
  • repeat:是否周期运行
  • active:是否启用
  • next:链表管理(多个定时器的组织方式)

这一结构设计具备高度拓展性,也适用于任何 MCU 平台。

API 函数声明:

void soft_timer_init(void);
soft_timer_t* soft_timer_create(uint32_t timeout, bool repeat, void (*callback)(void*), void* user_data);
void soft_timer_start(soft_timer_t* timer);
void soft_timer_stop(soft_timer_t* timer);
void soft_timer_delete(soft_timer_t* timer);
void soft_timer_update(void); // 通常在 SysTick 或 1ms 中断中调用

使用流程概览

一个典型的软件定时器使用流程如下:

soft_timer_init(); // 初始化链表

// 创建一个500ms周期定时器
soft_timer_t* my_timer = soft_timer_create(500, true, led_toggle, NULL);
soft_timer_start(my_timer);

在系统时钟中断中(比如 1ms SysTick)调用:

void SysTick_Handler(void) {
    soft_timer_update(); // 每1ms调用一次,驱动全部定时器运行
}

示例:LED 闪烁不再繁琐

传统的 HAL 定时器实现 LED 闪烁,至少需要:

  • 配置 TIMx 寄存器
  • 编写中断服务函数
  • 开启中断优先级
  • 注册 HAL 回调或用户 ISR

使用 soft_timer 后,仅需几行:

void led_blink(void* arg) {
    HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}

soft_timer_t* blink_timer = soft_timer_create(500, true, led_blink, NULL);
soft_timer_start(blink_timer);

优雅、解耦、可重用,项目可读性也大大提升。

场景应用拓展

场景

使用建议

UI动画/按键消抖

使用 repeat=false 的一次性定时器

报文超时机制

回调中重置定时器实现“自动重传”

网络心跳包

使用周期定时器发送 ping

多任务调度(非RTOS)

多个定时器绑定不同任务函数

这种模式可以轻松取代状态机中复杂的超时判断逻辑,让主循环代码更“干净”。

和 RTOS 配合使用?

当然可以!即便你用了 FreeRTOS 等系统,soft_timer 依旧能在任务级别独立管理时间任务,尤其适合:

  • low_priority 后台逻辑管理
  • 在不便使用 RTOS 的中断上下文中触发定时任务
  • 替代 vTaskDelay 更精细地控制短延迟

注意:只需保证 soft_timer_update() 运行在一个固定节拍中(RTOS 中通常放在 tick hook 或后台任务)。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言