software-timer
2025-09-07 19:40:49

软件定时器和硬件定时器

  1. 硬件定时器:芯片内部的一个独立外设单元(stm32中TIM1等)。
  2. 软件定时器:基于系统时钟中断且由软件来模拟的定时器,当经过设定的Tick 时钟计数值后会触发用户定义的回调函数。软件定时器本身基本不占用CPU资源,只有在回调函数被执行时才会用到CPU。

为了启用软件定时器,需要在头文件FreeRTOSConfig.h中设置configUSE_TIMERS的值为1。

回调函数原型:

1
void ATimerCallback( TimerHandle_t xTimer );
  • xTimer是定时器句柄
  • 回调函数代码应该尽可能地简短紧凑,并且避免调用FreeRTOS的API函数防止进入阻塞状态。

软件定时器的状态

  • 静止状态(Dormant):处于静止装态的定时器不会执行回调函数,可以通过调用定时器的句柄启用
  • 运行状态(Running):处于运行状态的定时器会在设定的时间间隔(相对于定时器进入运行状态后)到达后调用回调函数。

软件定时器类型

  1. 一次性定时器(One-shot timer):启动后只会执行一次回调函数。
  • 一次性定时器会在执行回调函数后进入静止状态
    One-shot
  1. 自动重载定时器(Auto-reload timer):周期性执行回调函数。
  • 自动重载定时器会在执行回调函数后重新进入运行状态
    Auto-reload

软件定时器实质

软件定时器是由一个系统内核调度器自动生成的时间服务任务(Timer Server Task)来管理。当创建并启动一个软件定时器时,定时器对象会被加入到时间服务任务管理的定时器列表里。时间服务任务会周期性检查这些定时器是否到期,到期则调用你注册的回调函数。
在FreeRTOSConfig.h中相关配置

  • configTIMER_TASK_PRIORITY:决定了时间服务任务的运行优先级。优先级越高,定时器到期后回调就能更快被执行。
  • configTIMER_TASK_STACK_DEPTH:决定了时间服务任务的栈大小(单位通常是字节或“栈深度”)。

避免在回调函数中调用会阻塞的FreeRTOS api,会阻塞时间服务任务,导致其他定时器无法及时处理,严重时影响系统定时精度甚至死锁。

软件定时器的启动、停止、重置等操作,并不是立即生效,而是通过“命令队列”发送到时间服务任务中去处理。
这个队列的长度由configTIMER_QUEUE_LENGTH决定。

图形化配置界面

cubemx
Callback选项是由用户实现的回调函数,Type选项可以选择一次性定时器或者自动重载定时器。

FreeRTOS 定时器相关 API 函数说明

  1. 创建定时器
1
2
3
4
5
TimerHandle_t xTimerCreate( const char * const pcTimerName,
TickType_t xTimerPeriodInTicks,
UBaseType_t uxAutoReload,
void * pvTimerID,
TimerCallbackFunction_t pxCallbackFunction )
  • 功能:创建定时器。
  • 参数说明
    • pcTimerName:定时器的名称,仅用于调试。
    • xTimerPeriodInTicks:定时器的周期(以tick为单位),可用pdMS_TO_TICKS()宏将毫秒转换为tick。
    • uxAutoReload:设为pdTRUE时为自动重载定时器,pdFALSE为一次性定时器。
    • pvTimerID:定时器的ID,可用于用户自定义目的。
    • pxCallbackFunction:定时器到期时执行的回调函数。
  • 返回值
    • NULL表示创建成功;
    • NULL表示创建失败。
  1. 启动定时器
1
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait )
  • 功能:启动定时器。
  • 参数说明
    • xTimer:要启动的定时器句柄。
    • xTicksToWait:如果命令队列已满,最多等待多少tick。
  • 返回值
    • pdPASS表示启动成功;
    • pdFALSE表示失败。
  1. 设置定时器ID
1
void vTimerSetTimerID( const TimerHandle_t xTimer, void *pvNewID )
  • 功能:设置定时器的pvTimerID属性。
  • 参数说明
    • xTimer:定时器句柄。
    • pvNewID:要设置的新ID值。
  1. 获取定时器ID
1
void *pvTimerGetTimerID( TimerHandle_t xTimer )
  • 功能:获取定时器的pvTimerID属性。
  • 参数说明
    • xTimer:定时器句柄。
  • 返回值pvTimerID的值。
  1. 改变定时器周期
1
2
3
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, 
TickType_t xNewTimerPeriodInTicks,
TickType_t xTicksToWait )
  • 功能:改变定时器的运行周期。
  • 参数说明
    • xTimer:定时器句柄。
    • xNewTimerPeriodInTicks:新的定时器周期(tick),可用pdMS_TO_TICKS()转换。
    • xTicksToWait:如果命令队列已满,最多等待多少tick。
  • 返回值
    • pdPASS表示成功;
    • pdFALSE表示失败。
  1. 重置定时器
1
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait )
  • 功能:重置定时器,重新开始计时。
  • 参数说明
    • xTimer:定时器句柄。
    • xTicksToWait:如果命令队列已满,最多等待多少tick。
  • 返回值
    • pdPASS表示成功;
    • pdFALSE表示失败。

定时器ID作用

  • 多个定时器共用同一个回调函数时,可以通过ID判断当前是哪个定时器触发
  • pvTimerID 是一个 void* 指针,可以指向任何类型的数据结构,如整型、结构体、数组等。可以在回调函数里获得上下文信息(如相关任务句柄、设备句柄、状态数据等)
1
2
3
4
void vTimerCallback(TimerHandle_t xTimer){
void *pvID = pvTimerGetTimerID(xTimer);
// 根据ID做不同的操作
}