高可靠的定时器事件总线需将定时器转为事件触发引擎,依托硬件定时器(如stm32高级/基础定时器)提供低抖动中断源,分层解耦触发、分发、消费,结合环形缓冲区、原子操作、看门狗监控与时间戳校验,并支持跨平台抽象与可测试设计。

构建高可靠的基于定时器的事件总线,关键不是堆砌功能,而是让定时器从“计时工具”转变为“事件触发引擎”。它需要硬件能力支撑、软件架构解耦、以及对异常场景的主动防御设计。
用硬件定时器做事件源,而非软件轮询
依赖 CPU 轮询或 Thread.Sleep 模拟定时,会引入调度抖动、精度漂移和功耗浪费。真正可靠的做法是把事件触发权交给硬件:
- 在 STM32 中,优先选用高级定时器(如 TIM1/TIM8)的更新中断(UIF)作为主事件源——它由计数器溢出/重载瞬间硬件置位,延迟固定且可预测;
- 基础定时器(TIM6/TIM7)虽无捕获比较功能,但其单一 Update 中断具有极低抖动和原子性,适合做系统心跳或看门狗喂狗等强实时任务;
- 避免在中断回调中做耗时操作,只负责发布事件(如写入无锁队列、置位原子标志),处理逻辑移交到主循环或专用工作线程。
事件总线需分层解耦:触发、分发、消费
把“谁来触发”、“怎么广播”、“谁来响应”三者彻底分离,才能实现可维护与可替换:
-
触发层:由一个或多个定时器实例驱动,每个实例绑定唯一事件类型(如
EVENT_MOTOR_STEP、EVENT_SENSOR_READ),通过 HAL 回调统一投递到事件池; - 分发层:采用环形缓冲区(Ring Buffer)+ 原子读写指针,支持多生产者(多个定时器)、单消费者(主循环)安全写入;不使用动态内存分配,所有事件结构体预分配;
- 消费层:主循环按优先级或时间戳顺序遍历事件队列,调用注册的处理器函数;支持事件过滤(如仅处理某设备 ID 的超时事件)和丢弃策略(满队列时丢弃低优先级事件)。
增强可靠性:超时检测、状态同步与故障自愈
单纯“准时触发”不等于“高可靠”,必须覆盖常见失效路径:
- 为每个周期性事件配置独立的软件看门狗计数器,若连续 N 次未收到对应定时器的更新中断,则判定该定时器通道异常,自动切换备用通道或上报错误;
- 在事件结构体中嵌入时间戳(来自 CNTPCT_EL0 或 DWT_CYCCNT),消费者可判断是否严重滞后,决定跳过、降级或重试;
- 关键事件(如电机停机指令)支持“确认回执”机制:发布后启动一个短时基础定时器等待 ACK 标志,超时则重发或触发安全降级(如强制关断 PWM 输出)。
跨平台与可测试性设计要点
即使目标是嵌入式,也应预留抽象接口,便于单元测试和仿真:
- 定义统一的
timer_event_bus_t接口,包含post()、dispatch()、register_handler()等方法; - 硬件定时器驱动封装为可注入模块(如
stm32_timer_driver),测试时可用 mock 驱动模拟精确 tick 注入; - 所有事件类型用枚举定义,禁止字符串匹配;事件数据结构体保持 POD 类型,确保跨编译器兼容与内存布局确定性。











