1. 软件定时器分为单次和自动重载两种。
  2. xTimerCreate只创建,xTimerStart才启动。
  3. 所有回调都在公共Timer Service Task中执行。
  4. 回调之间是串行的。
  5. 回调必须短小,不能长时间阻塞。
  6. 耗时工作应通过Queue或Notification交给普通任务。
  7. 单次Timer到期后停止。
  8. 自动重载Timer到期后安排下一周期。

FreeRTOS软件定时器用于:

经过一段时间后执行回调
或者
按照固定周期反复执行回调

创建定时器

周期定时器

static TimerHandle_t xPeriodicTimer = NULL;

//名称:Periodic, 周期:400 Tick, 自动重载:pdTRUE, Timer ID:NULL,回调函数:vPeriodicTimerCallback
xTimerCreate("Periodic",pdMS_TO_TICKS(400),pdTRUE,NULL,vPeriodicTimerCallback);

static void vPeriodicTimerCallback(TimerHandle_t xTimer)
{
    if (condition)
    {
        (void)xTimerStop(xTimer, 0); //主动停止周期定时器
    }
}

单次定时器

static TimerHandle_t xOneShotTimer = NULL;
//名称:Periodic, 周期:100Tick, 自动重载:pdFALSE, Timer ID:NULL,回调函数:vOneShotTimerCallback
xTimerCreate("OneShot",pdMS_TO_TICKS(100),pdFALSE,NULL,vOneShotTimerCallback);

static void vOneShotTimerCallback(TimerHandle_t xTimer)
{
    (void)xTimer;
}

启动定时器

//启动哪个定时器,第二个参数:向Timer命令队列发送启动命令时,最多等待多少Tick
BaseType_t xPeriodicStartResult = xTimerStart(xPeriodicTimer, 0); 
BaseType_t xOneShotStartResult = xTimerStart(xOneShotTimer, 0);

软件定时器不是独立任务

每个软件定时器并没有自己的任务和任务栈。

FreeRTOS只创建一个公共任务:

Timer Service Task

也称:

Timer Daemon Task

所有软件定时器回调都由这个任务执行:

Timer Service Task
├── 调用Periodic回调
├── 调用One-shot回调
└── 调用其他软件定时器回调

所以定时器回调是串行执行的,不会同时运行。

Timer Service Task优先级

配置:

#define configTIMER_TASK_PRIORITY \
    (configMAX_PRIORITIES - 1)

回调不能阻塞

所有Timer共享一个Timer Service Task。

因此Timer回调中不要使用:

vTaskDelay()
xQueueReceive(..., portMAX_DELAY)
xSemaphoreTake(..., portMAX_DELAY)
长时间循环
慢速外设操作

回调中应该做什么

推荐:

设置标志
发送任务通知
发送短队列消息
启动或停止另一个Timer

常用Timer API

xTimerCreate()        /* 创建 */
xTimerStart()         /* 启动 */
xTimerStop()          /* 停止 */
xTimerReset()         /* 从当前时刻重新计时 */
xTimerChangePeriod()  /* 修改周期 */
xTimerDelete()        /* 删除 */
xTimerIsTimerActive() /* 查询是否活动 */