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中断。

验证步骤:

  1. 在main()中初始化HAL库和SysTick,然后创建两个定时器:一个硬件定时器(周期100ms,回调翻转LED1),一个软件定时器(周期500ms,回调翻转LED2)。
  2. 调用delay_ms(1000)延时,观察LED1每100ms翻转一次(1秒内翻转10次),LED2每500ms翻转一次(1秒内翻转2次)。
  3. 调用timer_stop()停止软件定时器,确认LED2停止翻转,LED1不受影响。

通过条件:LED翻转频率与设定周期一致,停止接口生效,延时函数阻塞时间准确(可用示波器测量IO翻转间隔验证)。

常见问题

  • 硬件定时器资源不足:增大hw_timers数组或改用其他定时器通道。
  • 软件定时器精度不足:1ms节拍下无法精确延时小于1ms的周期,此时应使用硬件定时器或忙等。
  • 回调中执行耗时操作:回调在中断上下文执行,应保持简短,复杂处理请使用标志位延后到主循环。