FreeRTOS-4-软件定时器管理

这是FreeRTOS系列学习文章的第四篇,主要介绍FreeRTOS软件定时器管理。

概述

软件计时器用于调度功能在将来的设定时间执行,或以固定频率定期执行。由软件定时器执行的函数称为软件定时器的回调函数

软件计时器由FreeRTOS内核实现,并受FreeRTOS内核的控制。它们不需要硬件支持,也与硬件计时器或硬件计数器无关。

软件计时器功能是可选的。要包括软件计时器功能,请执行以下操作:

  • 将FreeRTOS源文件FreeRTOS/Source/timers.c构建为项目的一部分
  • 在FreeRTOSConfig.h中将configUSE_TIMERS设置为1。

定时器回调函数

函数原型:

1
void ATimerCallback( TimerHandle_t xTimer );

其参数为:
软件定时器的唯一句柄

软件定时器的属性和状态

软件定时器分为

  • 一次性定时器: 一旦启动则只执行一次,并且不会自动重新执行,可以手动重新执行
  • 自动重新加载计时器: 一旦启动,自动重新加载计时器将在每次到期时重新启动,从而定期执行其回调函数。

软件定时器的状态

有两种状态:

  • 休眠状态
  • 运行状态


上面这张图显示了软件定时器的状态之间的转换

软件定时器的上下文

RTOS的守护任务

所有软件计时器回调函数都在同一RTOS守护进程(或“计时器服务”)任务的上下文中执行

该任务过去被称为“计时器服务任务”,因为最初它只用于执行软件计时器回调函数。现在同一任务也用于其他目的,因此它被称为“RTOS守护程序任务”的更一般的名称。

守护程序任务,是在启动调度程序时,自动创建的标准FreeRTOS任务。其优先级和堆栈大小分别由configTIMER_TASK_PRIORITYconfigTIMER_TASK_STACK_DEPTH编译时间配置常量设置。这两个常量都在FreeRTOSConfig.h中定义。

软件计时器回调函数不得调用会导致调用任务进入阻塞状态的FreeRTOS API函数,否则将导致守护程序任务进入阻塞状态。

计时器命令队列

计时器命令队列是在启动调度程序时自动创建的标准FreeRTOS队列。定时器命令队列的长度由FreeRTOSConfig.h中的configTIMER_QUEUE_LENGTH编译时间配置常量设置。

软件计时器API函数将命令从调用任务发送到称为“计时器命令队列”的队列上的守护程序任务。

守护程序任务与任何其他FreeRTOS任务一样进行调度;当守护程序任务是能够运行的最高优先级任务时,它只会处理命令或执行计时器回调函数。

创建软件定时器

函数xTimerCreate()可以创建一个软件定时器

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 以刻度为单位指定的计时器周期。pdMS_TO_TICKS()宏可用于将以毫秒为单位指定的时间转换为以计时单位指定的时间。
uxAutoReload uxAutoReload设置为pdTRUE以创建自动重新加载计时器。将uxAutoReload设置为pdFALSE以创建一次性计时器
pvTimerID 初始化ID。每个软件定时器都有一个ID值。ID是一个空指针,应用程序编写器可以将其用于任何目的。当多个软件计时器使用相同的回调函数时,ID特别有用,因为它可用于提供特定于计时器的存储。
本章中的一个示例演示了计时器ID的使用。 pvTimerID设置正在创建的任务的ID的初始值。
pxCallbackFunction 软件计时器回调函数仅仅是符合清单72中所示原型的C函数。pxCallbackFunction参数是指向要用作正在创建的软件计时器的回调函数的函数指针(实际上就是函数名)。
返回值 如果返回NULL,则无法创建软件计时器,因为FreeRTOS没有足够的堆内存来分配必要的数据结构。返回的非NULL值表示软件计时器已成功创建。返回值是创建的计时器的句柄。 第2章提供了有关堆内存管理的更多信息。

软件定时器开启/关闭函数

xTimerStart()用于启动处于休眠状态的软件定时器,或重置(重新启动)处于运行状态的软件定时器。xTimerStop()用于停止处于运行状态的软件计时器。停止软件计时器与将计时器转换到休眠状态相同。

可以在调度程序启动之前调用xTimerStart(),但是当这样做时,软件计时器直到调度程序启动时才会实际启动。

xTimerStart()函数

1
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );

参数说明:

参数/返回值 描述
xTimer 正在启动或重置的软件计时器的句柄。句柄将从用于创建软件计时器的xTimerCreate()调用中返回。
xTicksToWait xTimerStart()使用计时器命令队列向守护程序任务发送“启动计时器”命令。

xTicksToWait指定如果队列已满,调用任务应保持在阻塞状态以等待计时器命令队列上的空间变为可用的最长时间。

如果xTicksToWait为零且计时器命令队列已满,则xTimerStart()将立即返回。

阻塞时间以滴答周期指定,因此它表示的绝对时间取决于滴答频率。宏pdMS_TO_TICKS()可用于将以毫秒为单位的时间转换为以滴答为单位的时间。

如果FreeRTOSConfig.h中的include_vTaskSuspend设置为1,则将xTicksToWait设置为portMAX_DELAY将导致调用任务无限期地保持在阻塞状态(没有超时),以等待定时器命令队列中的空间变得可用。

如果在调度程序启动之前调用xTimerStart(),则会忽略xTicksToWait的值,并且xTimerStart()的行为就像xTicksToWait已设置为零一样。
返回值 有两个可能的返回值
1. pdPASS

只有当“启动定时器”命令成功发送到定时器命令队列时,才会返回pdPASS。

如果守护程序任务的优先级高于调用xTimerStart()的任务的优先级,那么调度程序将确保在xTimerStart()返回之前处理启动命令。这是因为一旦计时器命令队列中有数据,守护进程任务就会抢占调用xTimerStart()的任务。

如果指定了阻塞时间(xTicksToWait不是零),则在函数返回之前,调用任务可能被置于阻塞状态,以等待计时器命令队列中的空间变为可用,但在块时间到期之前,数据已成功写入计时器命令队列。

2.pdFALSE

如果由于队列已满而无法将“启动定时器”命令写入定时器命令队列,则将返回pdFALSE。

如果指定了阻塞时间(xTicksToWait不是零),则调用任务将被置于阻塞状态,以等待守护进程任务在计时器命令队列中腾出空间,但指定的阻塞时间在此之前已过期。

软件定时器ID

软件定时器ID是一个void*类型的值,所以可以将其转换为各种类型的数据。

创建软件计时器时会为ID分配初始值-之后可以使用vTimerSetTimerID()API函数更新ID,并使用pvTimerGetTimerID()API函数进行查询。

更改定时器的周期

软件定时器的作用实际上是计时,在设置的时间到达后执行指定的函数。

使用xTimerChangePeriod()函数更改软件计时器的周期。

1
2
3
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,  
TickType_t xNewTimerPeriodInTicks,
TickType_t xTicksToWait );

FreeRTOS-4-软件定时器管理
https://ysc2.github.io/ysc2.github.io/2024/01/16/FreeRTOS-4-软件定时器管理/
作者
Ysc
发布于
2024年1月16日
许可协议