4. 定时器抽象层实现
任务目标
在嵌入式项目中,应用层代码常直接操作芯片寄存器或厂商SDK的定时器API,导致定时器相关逻辑与具体硬件强耦合,难以在不同MCU平台间复用。本案例的目标是设计一个轻量级定时器抽象层,统一封装硬件定时器与软件定时器的初始化、启动、停止及回调注册接口,并基于该抽象层实现一个平台无关的延时函数。
核心设计
抽象层定义统一操作接口,底层分别实现硬件定时器驱动与软件定时器驱动。上层应用(如延时函数)只依赖抽象接口,不感知具体实现。软件定时器基于系统节拍(SysTick)中断轮询计数实现,不占用额外硬件定时器资源。
关键完整代码
/* timer_abstraction.h */
#ifndef TIMER_ABSTRACTION_H
#define TIMER_ABSTRACTION_H
#include <stdint.h>
typedef enum {
TIMER_TYPE_HARDWARE = 0,
TIMER_TYPE_SOFTWARE
} timer_type_t;
typedef void (*timer_callback_t)(void *arg);
typedef struct {
timer_type_t type;
uint32_t period_us; /* 定时周期,单位微秒 */
timer_callback_t callback;
void *arg;
} timer_config_t;
typedef struct timer_handle timer_handle_t;
/* 抽象层统一接口 */
timer_handle_t *timer_create(const timer_config_t *cfg);
void timer_start(timer_handle_t *handle);
void timer_stop(timer_handle_t *handle);
void timer_destroy(timer_handle_t *handle);
/* 基于抽象层实现的延时函数(阻塞) */
void delay_us(uint32_t us);
void delay_ms(uint32_t ms);
#endif /* TIMER_ABSTRACTION_H */
/* timer_abstraction.c */
#include "timer_abstraction.h"
#include <stdlib.h>
/* ---------- 硬件定时器底层(以STM32通用定时器为例) ---------- */
#include "stm32f1xx_hal.h"
typedef struct {
TIM_HandleTypeDef htim;
timer_callback_t cb;
void *arg;
} hw_timer_t;
static hw_timer_t hw_timers[4]; /* 最多支持4路硬件定时器 */
static uint8_t hw_timer_used[4] = {0};
static void hw_timer_irq_handler(TIM_HandleTypeDef *htim) {
for (int i = 0; i < 4; i++) {
if (&hw_timers[i].htim == htim) {
if (hw_timers[i].cb) hw_timers[i].cb(hw_timers[i].arg);
break;
}
}
}
/* 硬件定时器创建:分配TIMx,配置为周期中断模式 */
static timer_handle_t *hw_timer_create(const timer_config_t *cfg) {
for (int i = 0; i < 4; i++) {
if (!hw_timer_used[i]) {
hw_timer_used[i] = 1;
hw_timers[i].cb = cfg->callback;
hw_timers[i].arg = cfg->arg;
/* 以TIM2-TIM5为例,实际需根据芯片映射 */
hw_timers[i].htim.Instance = (TIM_TypeDef *)(TIM2_BASE + i * 0x400);
hw_timers[i].htim.Init.Prescaler = 72 - 1; /* 72MHz/72 = 1MHz */
hw_timers[i].htim.Init.CounterMode = TIM_COUNTERMODE_UP;
hw_timers[i].htim.Init.Period = cfg->period_us - 1; /* 1MHz计数,period_us即周期 */
hw_timers[i].htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&hw_timers[i].htim);
HAL_TIM_Base_Start_IT(&hw_timers[i].htim);
return (timer_handle_t *)&hw_timers[i];
}
}
return NULL; /* 资源不足 */
}
/* ---------- 软件定时器底层(基于SysTick 1ms节拍) ---------- */
typedef struct {
uint32_t remaining_ms;
uint32_t reload_ms;
uint8_t active;
timer_callback_t cb;
void *arg;
} sw_timer_t;
#define MAX_SW_TIMERS 8
static sw_timer_t sw_timers[MAX_SW_TIMERS];
static volatile uint32_t sys_tick_ms = 0;
void SysTick_Handler(void) {
sys_tick_ms++;
for (int i = 0; i < MAX_SW_TIMERS; i++) {
if (sw_timers[i].active) {
if (--sw_timers[i].remaining_ms == 0) {
sw_timers[i].active = 0;
if (sw_timers[i].cb) sw_timers[i].cb(sw_timers[i].arg);
}
}
}
}
static timer_handle_t *sw_timer_create(const timer_config_t *cfg) {
for (int i = 0; i < MAX_SW_TIMERS; i++) {
if (!sw_timers[i].active) {
sw_timers[i].reload_ms = (cfg->period_us + 999) / 1000;
sw_timers[i].remaining_ms = sw_timers[i].reload_ms;
sw_timers[i].cb = cfg->callback;
sw_timers[i].arg = cfg->arg;
sw_timers[i].active = 1;
return (timer_handle_t *)&sw_timers[i];
}
}
return NULL;
}
/* ---------- 抽象层接口实现 ---------- */
timer_handle_t *timer_create(const timer_config_t *cfg) {
if (!cfg || !cfg->callback) return NULL;
if (cfg->type == TIMER_TYPE_HARDWARE)
return hw_timer_create(cfg);
else
return sw_timer_create(cfg);
}
void timer_start(timer_handle_t *handle) {
if (!handle) return;
/* 硬件定时器已在create时启动,此处仅对软件定时器生效 */
sw_timer_t *sw = (sw_timer_t *)handle;
if (sw->active == 0) {
sw->remaining_ms = sw->reload_ms;
sw->active = 1;
}
}
void timer_stop(timer_handle_t *handle) {
if (!handle) return;
sw_timer_t *sw = (sw_timer_t *)handle;
sw->active = 0;
}
void timer_destroy(timer_handle_t *handle) {
if (!handle) return;
timer_stop(handle);
/* 硬件定时器需额外关闭HAL定时器,此处简化处理 */
}
/* ---------- 基于抽象层的延时函数 ---------- */
void delay_us(uint32_t us) {
timer_config_t cfg;
cfg.type = TIMER_TYPE_SOFTWARE;
cfg.period_us = us;
cfg.callback = NULL; /* 延时不需要回调 */
cfg.arg = NULL;
timer_handle_t *t = timer_create(&cfg);
if (!t) return;
/* 软件定时器最小精度1ms,us延时需忙等补偿 */
while (1) {
sw_timer_t *sw = (sw_timer_t *)t;
if (!sw->active) break;
}
timer_destroy(t);
}
void delay_ms(uint32_t ms) {
while (ms--) {
delay_us(1000);
}
}
运行与验证
环境依赖:STM32F1系列HAL库(或替换为其他平台驱动),Cortex-M内核SysTick已配置为1ms中断。
验证步骤:
- 在
main()中初始化HAL库和SysTick,然后创建两个定时器:一个硬件定时器(周期100ms,回调翻转LED1),一个软件定时器(周期500ms,回调翻转LED2)。 - 调用
delay_ms(1000)延时,观察LED1每100ms翻转一次(1秒内翻转10次),LED2每500ms翻转一次(1秒内翻转2次)。 - 调用
timer_stop()停止软件定时器,确认LED2停止翻转,LED1不受影响。
通过条件:LED翻转频率与设定周期一致,停止接口生效,延时函数阻塞时间准确(可用示波器测量IO翻转间隔验证)。
常见问题
- 硬件定时器资源不足:增大
hw_timers数组或改用其他定时器通道。 - 软件定时器精度不足:1ms节拍下无法精确延时小于1ms的周期,此时应使用硬件定时器或忙等。
- 回调中执行耗时操作:回调在中断上下文执行,应保持简短,复杂处理请使用标志位延后到主循环。