提示:好记性不如烂笔头。本博客作为学习笔记,有错误的地方希望指正
文章目录
- 前言:
- 一、xTimerCreate()
- 二、xTimerCreateStatic()
- 三、xTimerIsTimerActive()
- 四、xTimerStart()
- 五、xTimerStop()
- 六、xTimerChangePeriod()
- 七、xTimerDelete()
- 八、xTimerReset()
- 九、xTimerStartFromISR()
- 十、xTimerStopFromISR()
- 十一、xTimerChangePeriodFromISR()
- 十二、xTimerResetFromISR()
- 十三、pvTimerGetTimerID()
- 十四、vTimerSetReloadMode()
- 十五、vTimerSetTimerID()
- 十六、xTimerGetTimerDaemonTaskHandle()
- 十七、xTimerPendFunctionCall()
- 十八、xTimerPendFunctionCallFromISR()
- 十九、pcTimerGetName()
- 二十、xTimerGetPeriod()
- 二一、xTimerGetExpiryTime()
- 二二、xTimerGetReloadMode()、uxTimerGetReloadMode()
- 二三、软件定时器示例
前言:
参考资料:FreeRTOS API参考
几乎所有的单片机都有自己的定时器,单片机的定时器是有限资源的,但是FreeRTOS给我们提供了软件定时器,软件定时器可以实现很多个,不像硬件定时器一样会有数量的限制。
一、xTimerCreate()
API原型:
TimerHandle_t xTimerCreate
( const char * const pcTimerName,
const TickType_t xTimerPeriod,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
创建一个新的软件定时器实例, 并返回一个可以引用定时器的句柄。
要使此 RTOS API 函数可用:
- configUSE_TIMERS 和 configSUPPORT_DYNAMIC_ALLOCATION 必须在 FreeRTOSConfig.h 中同时设置为 1(configSUPPORT_DYNAMIC_ALLOCATION 也可以不定义,此时其默认值为 1)。
- FreeRTOS/Source/timers.c C 源文件必须包含在 构建中。
每个软件定时器都需要少量 RAM 来保存定时器的状态。 如果使用 xTimerCreate() 创建定时器, 则此 RAM 由 FreeRTOS 堆自动分配。 如果使用 xTimerCreateStatic() 创建软件定时器, 则 RAM 由应用程序编写器提供,这需要用到一个附加参数, 但允许在编译时静态分配 RAM 。 请参阅静态分配与 动态分配页面了解更多信息。
定时器是在休眠状态下创建的。 xTimerStart()、 xTimerReset()、 xTimerStartFromISR()、 xTimerResetFromISR()、 xTimerChangePeriod() 以及 xTimerChangePeriodFromISR() API 函数都可以用于将定时器转换为活动状态。
参数:
pcTimerName 分配给定时器的可读文本名称。 这样做纯粹是为了协助 调试。 RTOS 内核本身只通过句柄引用定时器, 而从不通过名字引用。
xTimerPeriod 定时器的周期。 以 tick 为单位指定此周期,宏 pdMS_TO_TICKS() 可用于将以毫秒为单位指定的时间转换为以 tick 为单位指定的时间。 例如, 如果定时器必须要在 100 次 tick 后到期,那么只需将 xTimerPeriod 设置为 100。 或者,如果定时器 必须在 500 毫秒后到期,则需要将 xTimerPeriod 设置为 pdMS_TO_TICKS( 500 )。 使用 pdMS_TO_TICKS() 的唯一前提条件是 configTICK_RATE_HZ 小于或等于 1000。 定时器周期必须大于 0。
uxAutoReload 如果 uxAutoReload 设置为 pdTRUE ,则定时器将按 xTimerPeriod 参数设置的频率重复到期。 如果 uxAutoReload 设置为 pdFALSE,则此定时器为一次性定时器, 它会在到期后进入休眠状态。
pvTimerID 分配给正在创建的定时器的标识符。 通常,此标识符用于定时器回调函数: 当同一个回调函数分配给了多个定时器时,此标识符可以识别哪个定时器已到期。 或者此标识符可与 vTimerSetTimerID() 和 pvTimerGetTimerID() API 函数一起使用, 以便保存调用 定时器回调函数之间的值。
pxCallbackFunction 定时器到期时调用的函数。 回调函数必须有 TimerCallbackFunction_t 定义的原型,即:
void vCallbackFunction( TimerHandle_t xTimer );
返回值:
如果定时器创建成功, 则返回新创建的定时器的句柄。 如果由于剩余的 FreeRTOS 堆不足以分配定时器结构体而无法创建定时器, 则返回 NULL。
用法示例:
#define NUM_TIMERS 5
/* 一个数组,用于保存创建的定时器的手柄。*/
TimerHandle_t xTimers[ NUM_TIMERS ];
/* 定义一个回调函数,该函数将被多个定时器实例所使用。
实例使用。 这个回调函数不做任何事情,只是计算
计时器过期的次数,并在计时器过期10次后停止计时器。
计时器过期10次后停止。 该计数被保存为
定时器的ID。*/
void vTimerCallback( TimerHandle_t xTimer )
{
const uint32_t ulMaxExpiryCountBeforeStopping = 10;
uint32_t ulCount;
/* 如果pxTimer参数为NULL,可以选择做一些事情。*/
configASSERT( xTimer );
/* 该定时器过期的次数被保存为该定时器的ID。
定时器的ID。 获取该计数。*/
ulCount = ( uint32_t ) pvTimerGetTimerID( xTimer );
/* 递增计数,然后测试定时器是否已经过期
ulMaxExpiryCountBeforeStopping了。*/
ulCount++;
/* 如果定时器已经过期10次,则停止其运行。*/
if( ulCount >= ulMaxExpiryCountBeforeStopping )
{
/* 如果从定时器回调函数中调用定时器API函数,请不要使用阻断时间。
如果从一个定时器回调函数中调用一个定时器API函数,不要使用阻断时间,因为这样做可能会导致
死锁! */
xTimerStop( xTimer, 0 );
}
else
{
/* 将增加的计数存回定时器的ID字段中
以便在下次这个软件定时器过期时可以再次读回它。
过期。*/
vTimerSetTimerID( xTimer, ( void * ) ulCount )。
}
}
void main( void )
{
long x;
/* 创建然后启动一些定时器。 在RTOS调度器启动之前启动计时器
在RTOS调度程序启动之前就开始计时,这意味着计时器将在RTOS调度程序启动后立即开始运行。
在RTOS调度程序启动前启动计时器,意味着计时器将在RTOS调度程序启动后立即开始运行。*/
for( x = 0; x < NUM_TIMERS; x++ )
{
xTimers[ x ] = xTimerCreate
( /* 只是一个文本名称,不被RTOS内核使用。
内核使用。*/
"定时器"。
/* 定时器的周期,以ticks为单位,必须大于0。
大于0。 */
( 100 * x ) + 100,
/* 计时器将在到期时自动重新加载
过期时自动重新加载。*/
pdTRUE,
/* 该ID用于存储计时器过期次数的计数。
计时器过期的次数。
被初始化为0。*/
( void * ) 0。
/* 每个定时器在过期时都会调用相同的回调。
过期时调用相同的回调。*/
vTimerCallback
);
if( xTimers[ x ] == NULL )
{
/* 定时器没有被创建。*/
}
else
{
/* 启动该定时器。 没有指定阻塞时间,即使有也会被忽略,因为RTOS
即使有,也会被忽略,因为RTOS的
调度器还没有启动。*/
if( xTimerStart( xTimers[ x ], 0 ) != pdPASS )
{
/* 定时器不能被设置为激活状态。
状态。*/
}
}
}
/* ...
在这里创建任务。
... */
/* 启动RTOS调度器将开始运行定时器
因为它们已经被设置为活动状态。*/
vTaskStartScheduler();
/* 不应到达这里。*/
for( ; ; )。
}
二、xTimerCreateStatic()
API原型:
TimerHandle_t xTimerCreateStatic(
const char * const pcTimerName,
const TickType_t xTimerPeriod,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction
StaticTimer_t *pxTimerBuffer );
创建一个新的软件定时器实例, 并返回一个可以引用定时器的句柄。
要使此 RTOS API 函数可用:
- configUSE_TIMERS 和 configSUPPORT_STATIC_ALLOCATION 都必须在 FreeRTOSConfig.h 中设置为 1。
- FreeRTOS/Source/timer.c C 源文件必须包含在构建中。
每个软件定时器都需要少量 RAM 来保存定时器的状态。 如果定时器是使用 xTimerCreate() 创建的, 则会从 FreeRTOS 堆中自动分配所需的 RAM。 如果软件定时器是使用 xTimerCreateStatic() 创建的, 则 RAM 由应用程序编写器提供,这需要用到一个附加参数, 但允许在编译时静态分配 RAM 。 请参阅静态分配与 动态分配页面了解更多信息。
定时器是在休眠状态下创建的。 xTimerStart()、 xTimerReset()、 xTimerStartFromISR()、 xTimerResetFromISR()、 xTimerChangePeriod() 以及 xTimerChangePeriodFromISR() API 函数都可以用于将定时器转换为活动状态。
参数:
pcTimerName 分配给定时器的可读文本名称。 这样做纯粹是为了协助 调试。 RTOS 内核本身只通过句柄引用定时器, 而从不通过名字引用。
xTimerPeriod 定时器的周期。 以 tick 为单位指定此周期,宏 pdMS_TO_TICKS() 可用于将以毫秒为单位指定的时间转换为以 tick 为单位指定的时间。 例如, 如果定时器必须要在 100 次 tick 后到期,那么只需将 xTimerPeriod 设置为 100。 或者,如果定时器 必须在 500 毫秒后到期,则需要将 xTimerPeriod 设置为 pdMS_TO_TICKS( 500 )。 使用 pdMS_TO_TICKS() 的唯一前提条件是 configTICK_RATE_HZ 小于或等于 1000。 定时器周期必须大于 0。
uxAutoReload 如果 uxAutoReload 设置为 pdTRUE ,则定时器将按 xTimerPeriod 参数设置的频率重复到期。 如果 uxAutoReload 设置为 pdFALSE,则此定时器为一次性定时器, 它会在到期后进入休眠状态。
pvTimerID 分配给正在创建的定时器的标识符。 通常,此标识符用于定时器回调函数: 当同一个回调函数分配给了多个定时器时,此标识符可以识别哪个定时器已到期。 或者此标识符可与 vTimerSetTimerID() 和 pvTimerGetTimerID() API 函数一起使用, 以便保存调用 定时器回调函数之间的值。
pxCallbackFunction 定时器到期时调用的函数。 回调函数必须有 TimerCallbackFunction_t 定义的原型,即:
void vCallbackFunction( TimerHandle_t xTimer );
pxTimerBuffer 必须指向 StaticTimer_t 类型的变量,然后 用该变量保存定时器的状态。
返回值:
如果定时器创建成功, 则返回新创建的定时器的句柄。 如果 pxTimerBuffer 为 NULL,则不会创建定时器, 同时返回 NULL。
用法示例:
pxTimerBuffer #define NUM_TIMERS 5
/* 一个数组,用于保存创建的定时器的手柄。*/
TimerHandle_t xTimers[ NUM_TIMERS ];
/* 一个StaticTimer_t结构的数组,用于存储每个创建的定时器的状态。
用于存储每个创建的定时器的状态。*/
StaticTimer_t xTimerBuffers[ NUM_TIMERS ];
/* 定义一个回调函数,将被多个定时器实例使用。
实例使用。 这个回调函数不做任何事情,只是计算相关定时器的
计时器过期的次数,并在计时器过期10次后停止该计时器。
计时器过期10次后停止。 该计数被保存为
定时器的ID。*/
void vTimerCallback( TimerHandle_t xTimer )
{
const uint32_t ulMaxExpiryCountBeforeStopping = 10;
uint32_t ulCount;
/* 如果pxTimer参数为NULL,可以选择做一些事情。*/
configASSERT( pxTimer );
/* 该定时器过期的次数被保存为该定时器的ID。
定时器的ID。 获取该计数。*/
ulCount = ( uint32_t ) pvTimerGetTimerID( xTimer );
/* 递增计数,然后测试定时器是否已经过期
ulMaxExpiryCountBeforeStopping了。*/
ulCount++;
/* 如果定时器已经过期10次,则停止其运行。*/
if( ulCount >= ulMaxExpiryCountBeforeStopping )
{
/* 如果从定时器回调函数中调用定时器API函数,请不要使用块状时间。
如果从一个定时器回调函数中调用一个定时器API函数,不要使用阻断时间,因为这样做可能会导致
死锁! */
xTimerStop( xTimer, 0 );
}
else
{
/* 将增加的计数存回定时器的ID字段中
以便在下次这个软件定时器过期时可以再次读回它。
过期。*/
vTimerSetTimerID( xTimer, ( void * ) ulCount );
}
}
void main( void )
{
long x;
/* 创建然后启动一些定时器。 在RTOS调度器启动之前启动计时器
在RTOS调度程序启动之前就开始计时,这意味着计时器将在RTOS调度程序启动后立即开始运行。
在RTOS调度程序启动前启动计时器,意味着计时器将在RTOS调度程序启动后立即开始运行。*/
for( x = 0; x < NUM_TIMERS; x++ )
{
xTimers[ x ] = xTimerCreateStatic
( /* 只是一个文本名称,不被RTOS内核使用。
内核使用。*/
"定时器"。
/* 定时器的周期,以ticks为单位,必须大于0。
大于0。 */
( 100 * x ) + 100,
/* 计时器将在到期时自动重新加载
过期时自动重新加载。*/
pdTRUE,
/* 该ID用于存储计时器过期次数的计数。
计时器过期的次数。
被初始化为0。*/
( void * ) 0。
/* 每个定时器在过期时都会调用相同的回调。
过期时调用相同的回调。*/
vTimerCallback,
/*传入一个StaticTimer_t变量的地址。
变量的地址,它将保存与正在创建的定时器相关的数据。
计时器的相关数据。*/
&( xTimerBuffers[ x ] )。
);
if( xTimers[ x ] == NULL )
{
/* 定时器没有被创建。*/
}
else
{
/* 启动该定时器。 没有指定阻塞时间,即使有也会被忽略,因为RTOS
即使有,也会被忽略,因为RTOS的
调度器还没有启动。*/
if( xTimerStart( xTimers[ x ], 0 ) != pdPASS )
{
/* 定时器不能被设置为激活状态。
状态。*/
}
}
}
/* ...
在这里创建任务。
... */
/* 启动RTOS调度器将开始运行定时器
因为它们已经被设置为活动状态。*/
vTaskStartScheduler();
/* 不应到达这里。*/
for( ; ; );
}
三、xTimerIsTimerActive()
API原型:
BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer );
查询软件定时器是否处于活动或休眠状态。
如果出现以下情况,定时器将处于休眠状态:
-
- 已创建但尚未启动,或这是一个尚未重启的过期的一次性计时器。
-
- 定时器是在休眠状态下创建的。 xTimerStart()、 xTimerReset()、 xTimerStartFromISR()、 xTimerResetFromISR()、 xTimerChangePeriod() 以及 xTimerChangePeriodFromISR() API 函数都可以用于将定时器转换为活动状态。
参数:
xTimer 被查询的定时器。
返回值:
如果定时器处于休眠状态,将返回 pdFALSE。 如果定时器处于活动状态,将返回 pdFALSE 以外的值。
用法示例:
/*此函数假定xTimer已经被创建。
已经创建。*/
void vAFunction( TimerHandle_t xTimer )
{
/* 或者更简单、更等价地
"if( xTimerIsTimerActive( xTimer ))" */
if( xTimerIsTimerActive( xTimer ) != pdFALSE )
{
/* xTimer是活动的,做一些事情。*/
}
else
{
/* xTimer没有被激活,做一些其他事情。*/
}
}
四、xTimerStart()
API原型:
BaseType_t xTimerStart( TimerHandle_t xTimer,TickType_t xBlockTime );
用法示例:
软件定时器功能由定时器服务/守护进程任务提供。 许多 公共 FreeRTOS 定时器 API 函数通过定时器命令队列 向定时器服务任务发送命令。 定时器命令队列是 RTOS 内核本身的私有队列, 应用程序代码无法直接访问该队列。 定时器命令队列的长度 由 configTIMER_QUEUE_LENGTH 配置常量设置。
xTimerStart() 启动先前使用 xTimerCreate() API 函数创建的定时器。 如果定时器已经启动且已处于活动状态, 那么 xTimerStart() 具有与 xTimerReset() API 函数等效的功能。
启动定时器可确保定时器处于活动状态。 如果定时器 在此期间没有被停用、删除或重置, 那么在调用 xTimerStart() 并经过了 “n” 个 tick 之后,将调用与定时器相关联的回调函数, 其中 “n” 表示规定的定时器周期。
在 RTOS 调度器启动之前调用 xTimerStart() 是有效的, 但是完成此操作后,直到启动 RTOS 调度器之前,定时器都不会真正启动, 并且定时器的到期时间与 RTOS 调度器的启动时间有关, 与调用 xTimerStart() 的时间无关。
configUSE_TIMERS 配置常量必须设置为 1,xTimerStart() 才可用。
参数:
xTimer 正在启动/重新启动的定时器的句柄。
xBlockTime 在调用 xTimerStart() 时队列已满的情况下, 指定调用任务应保持阻塞状态 以等待启动命令成功发送到定时器命令队列的时间 (以 tick 为单位)。 如果在 启动 RTOS 调度器之前调用 xTimerStop(),则会忽略 xBlockTime。
返回值:
如果即便经过了 xBlockTime(以 tick 为单位)后启动命令仍无法发送到定时器命令队列,则返回 pdFAIL。 如果该命令成功发送到定时器命令队列, 则返回 pdPASS。 实际处理命令的时间取决于 定时器服务/守护进程任务相对于系统中其他任务的优先级, 尽管定时器到期时间与实际调用 xTimerStart() 的时间有关。 定时器 服务/守护进程任务的优先级由 configTIMER_TASK_PRIORITY 配置常量设置。
五、xTimerStop()
API原型:
BaseType_t xTimerStop( TimerHandle_t xTimer,TickType_t xBlockTime );
软件定时器功能由定时器服务/守护进程任务提供。 许多 公共 FreeRTOS 定时器 API 函数通过定时器命令队列 向定时器服务任务发送命令。 定时器命令队列是 RTOS 内核本身的私有队列, 应用程序代码无法直接访问该队列。 定时器命令队列的长度 由 configTIMER_QUEUE_LENGTH 配置常量设置。
xTimerStop() 停止先前使用 xTimerStart()、 xTimerReset()、 xTimerStartFromISR()、 xTimerResetFromISR()、 xTimerChangePeriod() 以及 xTimerChangePeriodFromISR() API 函数之一启动的定时器。
停用定时器可确保定时器不处于活动状态。
configUSE_TIMERS 配置常量必须设置为 1,xTimerStop() 才可用。
参数:
xTimer 正在停止的定时器的句柄。
xBlockTime 在调用 xTimerStop() 时队列已满的情况下, 指定调用任务应保持阻塞状态 以等待停止命令成功发送到定时器命令队列的时间 (以 tick 为单位)。 如果在 启动 RTOS 调度器之前调用 xTimerStop(),则会忽略 xBlockTime。
返回值:
如果即使经过了 xBlockTime(以 tick 为单位)之后, 停止命令仍无法发送到定时器命令队列,则返回 pdFAIL。 如果该命令成功发送到定时器命令队列, 则返回 pdPASS。 实际处理命令的时间取决于 定时器服务/守护进程任务相对于系统中其他任务的优先级。 定时器服务/守护进程任务的优先级由 服务/守护进程任务的优先级由 configTIMER_TASK_PRIORITY 配置常量设置。
六、xTimerChangePeriod()
API原型:
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,
TickType_t xNewPeriod,
TickType_t xBlockTime );
软件定时器功能由定时器服务/守护进程任务提供。 许多 公共 FreeRTOS 定时器 API 函数通过定时器命令队列 向定时器服务任务发送命令。 定时器命令队列是 RTOS 内核本身的私有队列, 应用程序代码无法直接访问该队列。 定时器命令队列的长度 由 configTIMER_QUEUE_LENGTH 配置常量设置。
xTimerChangePeriod() 可以改变先前使用 xTimerCreate() API 函数创建的定时器的周期。
可以调用 xTimerChangePeriod() 来更改活动 或休眠状态的定时器的周期。 更改休眠定时器的周期也会启动 定时器。
必须将 configUSE_TIMERS 配置常量设置为 1, xTimerChangePeriod() 才可用。
参数:
xTimer 正在更改其周期的定时器的句柄。
xNewPeriod xTimer 的新周期。定时器周期 在 tick 周期中指定,因此常量 portTICK_PERIOD_MS 可用于转换 已指定的时间(以毫秒为单位)。 例如,如果定时器必须 在100个 tick 后过期,则 xNewPeriod 应设置为100。 或者, 如果定时器必须在500 毫秒后过期,则 xNewPeriod 可以设置为 (500/portTICK_PERIOD_MS) ,前提是 configTICK_RATE_HZ 小于 或等于 1000。
xBlockTime 在调用 xTimerDelete() 时队列已满的情况下, 指定调用任务应保持阻塞状态 以等待变更周期命令成功发送到定时器命令队列的时间 (以 tick 为单位)。 如果在 启动 RTOS 调度器之前调用 xTimerChangePeriod(),则会忽略 xBlockTime。
返回值:
如果即使经过 xBlockTime(以 tick 为单位) 之后仍无法将更改周期命令发送到定时器命令队列,则将返回 pdFAIL。 如果能将此命令成功发送到定时器命令队列,则返回 pdPASS 则返回 pdPASS。 实际处理命令的时间取决于 定时器服务/守护进程任务相对于系统中其他任务的 优先级。 定时器服务/守护进程任务的优先级 由 configTIMER_TASK_PRIORITY 配置常量设置。
用法示例:
/*此函数假定xTimer已经被创建。 如果在调用该函数时,xTimer所引用的定时器
所引用的定时器已经激活,那么该定时器将被删除。
将被删除。 如果xTimer引用的定时器在它被调用时没有被激活,那么该定时器的周期被设置为
计时器的周期被设置为500ms,并且计时器被启动。
启动。*/
void vAFunction( TimerHandle_t xTimer )
{
/* 或者更简单、更等价地
"if( xTimerIsTimerActive( xTimer ))" */
if( xTimerIsTimerActive( xTimer ) != pdFALSE )
{
/* xTimer已经处于活动状态 - 删除它。*/
xTimerDelete( xTimer );
}
else
{
/* xTimer未被激活,将其周期改为500ms。 这也将
导致定时器启动。 如果改变周期的命令不能立即发送给定时器,则最多阻断100次。
如果改变周期的命令不能立即被发送到定时器的
命令队列。*/
if( xTimerChangePeriod( xTimer, 500 / portTICK_PERIOD_MS, 100 ) == pdPASS )
{
/* 该命令已成功发送。*/
}
else
{
/* 该命令无法被发送,即使在等待了100次后
也无法发送。 在这里采取适当的行动。*/
}
}
}
七、xTimerDelete()
API原型:
BaseType_t xTimerDelete( TimerHandle_t xTimer,TickType_t xBlockTime );
软件定时器功能由定时器服务/守护进程任务提供。 许多 公共 FreeRTOS 定时器 API 函数通过定时器命令队列 向定时器服务任务发送命令。 定时器命令队列是 RTOS 内核本身的私有队列, 应用程序代码无法直接访问该队列。 定时器命令队列的长度 由 configTIMER_QUEUE_LENGTH 配置常量设置。
xTimerDelete() 可删除以前使用 xTimerCreate() API 函数创建的定时器。请注意,删除静态分配的定时器时,在 xTimerIsTimerActive() 指示该定时器处于非活动状态之前,无法重复使用其静态内存。
必须将 configUSE_TIMERS 配置常量设置为 1, xTimerDelete() 才可用。
参数:
xTimer 正在删除的定时器的句柄。
xBlockTime 在调用 xTimerDelete() 时队列已满的情况下, 指定调用任务应保持阻塞状态 以等待删除命令成功发送到定时器命令队列的时间 (以 tick 为单位)。 如果 在 RTOS 调度器启动之前调用 xTimerDelete(),则忽略 xBlockTime。
返回值:
如果即使经过 xBlockTime(以 tick 为单位) 之后仍无法将删除命令发送到定时器命令队列,则将返回 pdFAIL。 如果能将此命令成功发送到定时器命令队列,则返回 pdPASS 则返回 pdPASS。 实际处理命令的时间取决于 定时器服务/守护进程任务相对于系统中其他任务的 优先级。 定时器服务/守护进程任务的优先级 由 configTIMER_TASK_PRIORITY 配置常量设置。
八、xTimerReset()
API原型:
BaseType_t xTimerReset( TimerHandle_t xTimer,TickType_t xBlockTime );
软件定时器功能由定时器服务/守护进程任务提供。 许多 公共 FreeRTOS 定时器 API 函数通过定时器命令队列 向定时器服务任务发送命令。 定时器命令队列是 RTOS 内核本身的私有队列, 应用程序代码无法直接访问该队列。 定时器命令队列的长度 由 configTIMER_QUEUE_LENGTH 配置常量设置。
xTimerReset() 重新启动先前使用 xTimerCreate() API 函数创建的定时器。 如果定时器已经启动且已处于活动状态, 那么 xTimerReset() 会使定时器 重新评估其到期时间,因此到期时间与 xTimerReset() 的调用时间有关。 如果定时器处于休眠状态,则 xTimerReset() 具有与 xTimerStart() API 函数等效的功能。
重置定时器可确保定时器处于活动状态。 如果定时器 在此期间没有被停用、删除或重置, 那么在调用 xTimerReset() 并经过了 “n” 个 tick 之后,将调用与定时器相关联的回调函数, 其中“n”表示规定的定时器周期。
在 RTOS 调度器启动之前调用 xTimerReset() 是有效的, 但是完成此操作后,直到启动 RTOS 调度器之前,定时器都不会真正启动, 并且定时器的到期时间与 RTOS 调度器的启动时间有关, 与调用 xTimerReset() 的时间无关。
configUSE_TIMERS 配置常量必须设置为 1,xTimerReset() 才可用。
参数:
xTimer 正在重置/启动/重新启动的定时器的句柄。
xBlockTime 在调用 xTimerReset() 时队列已满的情况下, 指定调用任务应保持阻塞状态 以等待重置命令成功发送到定时器命令队列的时间 (以 tick 为单位)。 如果在 启动 RTOS 调度器之前调用 xTimerReset(),则忽略 xBlockTime。
返回值:
如果即使经过 xBlockTime(以 tick 为单位) 之后仍无法将重置命令发送到定时器命令队列,则返回 pdFAIL。 如果能将此命令成功发送到定时器命令队列,则返回 pdPASS 。 实际处理命令的时间取决于 定时器服务/守护进程任务相对于系统中其他任务的优先级, 尽管定时器到期时间与实际调用 xTimerReset() 的时间有关。 定时器 服务/守护进程任务的优先级由 configTIMER_TASK_PRIORITY 配置常量设置。
用法示例:
/* 当一个键被按下时,LCD背光灯被打开。 如果5秒钟过去了
5秒后没有按键,那么LCD背光就会关闭。 在这种情况下
在这种情况下,该定时器是一个一次性的定时器。*/
TimerHandle_t xBacklightTimer = NULL。
/* 分配给一次性定时器的回调函数。 在这种情况下
参数不被使用。*/
void vBacklightTimerCallback( TimerHandle_t pxTimer )
{
/* 计时器过期了,因此在按下一个键之后,必须有5秒钟的时间。
计时器已经过期,因此必须在按下一个键之后过了5秒钟。 关闭LCD背光灯。*/
vSetBacklightState( BACKLIGHT_OFF )。
}
/* 按键事件处理程序。*/
void vKeyPressEventHandler( char cKey )
{
/* 确保LCD背光灯打开,然后重置负责在5秒后关闭背光灯的计时器。
负责在按键不活动5秒后关闭背光灯的计时器。
5秒后关闭背光。 如果不能立即发送命令,则等待10秒钟后成功发送。
如果不能立即发送。*/
vSetBacklightState( BACKLIGHT_ON )。
if( xTimerReset( xBacklightTimer, 10 ) != pdPASS )
{
/* 重置命令没有成功执行。 采取适当的
在这里采取适当的行动。*/
}
/* 在此执行其余的按键处理。*/
}
void main( void )
{
long x;。
/* 创建并启动单次定时器,负责在5秒内没有按键时关闭背光灯。
如果在5秒钟内没有按任何键,则负责关闭背光灯。*/
xBacklightTimer = xTimerCreate
(
/* 只是一个文本名称,不被RTOS内核使用。*/
"BacklightTimer",
/* 定时器的周期,以ticks为单位。*/
( 5000 / portTICK_PERIOD_MS)。
/* 定时器是一个一次性的定时器。*/
pdFALSE,
/* id不被回调使用,所以可以使用任何值。
值。*/
0,
/* 回调函数,用于关闭LCD背光。
关闭的回调函数。*/
vBacklightTimerCallback
);
if( xBacklightTimer == NULL )
{
/* 定时器没有被创建。*/
}
else
{
/* 启动该定时器。 没有指定阻塞时间,即使指定了
也会被忽略,因为RTOS的调度程序还没有被启动。
启动。*/
if( xTimerStart( xBacklightTimer, 0 ) != pdPASS )
{
/* 定时器不能被设置为激活状态。*/
}
}
/* ...
在这里创建任务。
... */
/* 启动RTOS调度器将启动定时器的运行,因为它已经被设置为活动状态。
已经被设置为活动状态。*/
vTaskStartScheduler()。
/* 不应到达这里。*/
for( ; ; )。
}
九、xTimerStartFromISR()
API原型:
BaseType_t xTimerStartFromISR(
TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken);
可从中断服务例程调用的 xTimerStart() 的版本。
参数:
xTimer 正在启动/重新启动的定时器的句柄。
pxHigherPriorityTaskWoken 定时器服务/守护进程任务大部分时间 都处于阻塞状态,等待消息到达定时器 命令队列。 调用 xTimerStartFromISR() 会将消息写入定时器 命令队列,从而让定时器服务/守护进程 任务有可能脱离阻塞状态。 如果调用 xTimerStartFromISR() 导致 定时器服务/守护进程任务脱离阻塞状态,且定时器服务/ 守护进程任务的优先级等于或大于当前执行的 任务(被中断的任务),那 *pxHigherPriorityTaskWoken 将在 xTimerStartFromISR() 函数内部被设置为 pdTRUE。 如果 xTimerStartFromISR() 将此值设置为 pdTRUE, 那应在中断退出前执行上下文切换。
返回值:
如果启动命令无法发送至定时器命令队列, 则返回 pdFAIL。 如果命令成功发送至定时器命令队列, 则返回 pdPASS。 实际处理命令的时间 取决于定时器服务/守护进程任务相对于系统中其他任务的优先级, 尽管定时器到期时间 是相对于实际调用 xTimerStartFromISR() 的时间而言。 定时器服务/守护进程 任务优先级由 configTIMER_TASK_PRIORITY 配置常量设置。
用法示例:
/* 本方案假设xBacklightTimer已经被创建。 当一个
键被按下时,LCD背光灯被打开。 如果5秒钟过去了
5秒后没有按键,LCD背光就会关闭。 在这种情况下
在这种情况下,定时器是一个一次性的定时器,与所给的例子不同的是
xTimerReset()函数的例子不同,按键事件处理程序是一个中断
服务例程。*/
/* 指派给一次性定时器的回调函数。 在这种情况下
参数不被使用。*/
void vBacklightTimerCallback( TimerHandle_t pxTimer )
{
/* 计时器过期了,因此在按下一个键之后,必须有5秒钟的时间。
计时器已经过期,因此必须在按下一个键之后过了5秒钟。 关闭LCD背光灯。*/
vSetBacklightState( BACKLIGHT_OFF )。
}
/* 按键中断服务例程。*/
void vKeyPressEventInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* 确保LCD背光灯是亮着的,然后重新启动负责关闭背光灯的定时器。
负责在按键不活动5秒后关闭背光灯的计时器。
键不活动后,重新启动负责关闭背光的计时器。 这是一个中断服务例程,所以只能
调用以 "FromISR "结尾的FreeRTOS API函数。*/
vSetBacklightState( BACKLIGHT_ON );
/* 这里可以调用xTimerStartFromISR()或xTimerResetFromISR()。
因为两者都会导致定时器重新计算其到期时间。
xHigherPriorityTaskWoken在声明时被初始化为pdFALSE。
声明时被初始化为pdFALSE(在这个函数中)。*/
if( xTimerStartFromISR( xBacklightTimer,&xHigherPriorityTaskWoken ) != pdPASS )
{
/* 启动命令没有成功执行。 采取适当的
在这里采取适当的行动。*/
}
/* 在此执行其余的键处理。*/
/* 如果xHigherPriorityTaskWoken等于pdTRUE,那么就应该进行上下文切换。
就应该执行上下文切换。 在ISR内部执行上下文切换所需的语法
所需的语法在不同的端口和不同的编译器中都有所不同。
编译器有所不同。 检查你正在使用的端口的演示,以找到
所需的实际语法。*/
if( xHigherPriorityTaskWoken != pdFALSE )
{
/* 在这里调用中断安全输出函数(实际函数
取决于正在使用的FreeRTOS端口)。*/
}
}
十、xTimerStopFromISR()
API原型:
BaseType_t xTimerStopFromISR(
TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken);
可从中断服务例程调用的 xTimerStop() 的版本。
参数:
xTimer 正在停止的定时器的句柄。
pxHigherPriorityTaskWoken 定时器服务/守护进程任务大部分时间 都处于阻塞状态,等待消息到达定时器 命令队列。 调用 xTimerStopFromISR() 会将消息写入 定时器命令队列,因此有可能将定时器服务/ 守护进程任务转换为非阻塞状态。 如果调用 xTimerStopFromISR(), 会导致定时器服务/守护进程任务退出阻塞状态,并且 守护进程任务的优先级等于或大于当前执行的 当前正在执行的任务(中断的任务),则会在 xTimerStopFromISR() 函数内部 将 *pxHigherPriorityTaskWoken 设置为 pdTRUE。 如果 xTimerStopFromISR() 将此值设置为 pdTRUE,则应在中断退出之前 那应在中断退出前执行上下文切换。
返回值:
如果即使经过了 xBlockTime(以 tick 为单位)之后, 则返回 pdFAIL。 如果命令成功发送至定时器命令队列, 则返回 pdPASS。 实际处理命令的时间 取决于定时器服务/守护进程任务相对于系统中其他任务的 优先级。 定时器服务/守护进程 任务优先级由 configTIMER_TASK_PRIORITY 配置常量设置。
用法示例:
/* 本方案假设xTimer已经被创建并启动。 当
中断发生时,定时器应该被简单地停止。*/
/*停止定时器的中断服务例程。*/
void vAnExampleInterruptServiceRoutine( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* 中断已经发生--只需停止定时器。
xHigherPriorityTaskWoken被设置为pdFALSE,它被定义在
(在这个函数中)。 由于这是一个中断服务例程,只有
FreeRTOS API中以 "FromISR "结尾的函数可以被使用。*/
if( xTimerStopFromISR( xTimer, &xHigherPriorityTaskWoken ) != pdPASS )
{
/* 停止命令没有成功执行。 采取适当的
在这里采取适当的行动。*/
}
/* 如果xHigherPriorityTaskWoken等于pdTRUE,那么就应该进行上下文切换。
应该被执行。 在ISR内部执行上下文切换所需的语法
所需的语法在不同的端口和不同的编译器中都有所不同。
编译器有所不同。 检查你正在使用的端口的演示,以找到
所需的实际语法。*/
if( xHigherPriorityTaskWoken != pdFALSE )
{
/* 在这里调用中断安全输出函数(实际函数
取决于正在使用的FreeRTOS端口)。*/
}
}
十一、xTimerChangePeriodFromISR()
API原型:
BaseType_t xTimerChangePeriodFromISR(
TimerHandle_t xTimer,
TickType_t xNewPeriod,
BaseType_t *pxHigherPriorityTaskWoken);
可从中断服务例程调用的 xTimerChangePeriod() 的版本。
参数:
xTimer 正在更改其周期的软件定时器的句柄。
xNewPeriod xTimer 的新周期。定时器周期 在 tick 周期中指定,因此常量 portTICK_PERIOD_MS 可用于转换 已指定的时间(以毫秒为单位)。 例如,如果定时器必须 在100个 tick 后过期,则 xNewPeriod 应设置为100。 或者, 如果定时器必须在500 毫秒后过期,则 xNewPeriod 可以设置为 (500/portTICK_PERIOD_MS) ,前提是 configTICK_RATE_HZ 小于 或等于1000。
pxHigherPriorityTaskWoken 定时器服务/守护进程任务大部分时间 都处于阻塞状态,等待消息到达定时器 命令队列。 调用 xTimerChangePeriodFromISR() 会将消息写入 定时器命令队列,因此有可能将定时器服务/ 守护进程任务转换为非阻塞状态。 如果调用 xTimerChangePeriodFromISR() 导致定时器服务/守护进程任务退出阻塞状态,并且 定时器服务/守护进程任务的优先级等于或大于 当前正在执行任务(被中断的任务) ,则 *pxHigherPriorityTaskWoken 将获得在 xTimerChangePeriodFromISR() 函数内部 设置为 pdTRUE 。 如果 xTimerChangePeriodFromISR() 将此值设置为 pdTRUE ,则应在中断退出前执行上下文切换 。
返回值:
如果更改定时器周期的命令无法发送到定时器命令队列, 则返回 pdFAIL 。 如果命令已成功发送到定时器命令队列, 则返回 pdPASS 。 实际处理命令的时间 将取决于定时服务/守护进程任务相对于系统中的其他任务的 优先级。 定时服务/守护进程任务 优先级由 configTIMER_TASK_PRIORITY 配置常量设置。
用法示例:
/* 本方案假设xTimer已经被创建并启动。 当时,xTimer的周期应该改变为500ms。*/
/*改变xTimer周期的中断服务程序。*/
void vAnExampleInterruptServiceRoutine( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* 中断已经发生--将xTimer的周期改为500ms。
xHigherPriorityTaskWoken被设置为pdFALSE,它被定义在
(在这个函数中)。 由于这是一个中断服务例程,只有
FreeRTOS API中以 "FromISR "结尾的函数可以被使用。*/
if( xTimerChangePeriodFromISR( xTimer,
pdMS_TO_TICKS( 500 ),
&xHigherPriorityTaskWoken ) != pdPASS )
{
/* 更改定时器周期的命令没有被成功执行。
成功执行。 在这里采取适当的行动。*/
}
/* 如果xHigherPriorityTaskWoken等于pdTRUE,那么就应该进行上下文切换。
应该被执行。 在ISR内部执行上下文切换所需的语法
所需的语法在不同的端口和不同的编译器中都有所不同。
编译器有所不同。 检查你正在使用的端口的演示,以找到
所需的实际语法。*/
if( xHigherPriorityTaskWoken != pdFALSE )
{
/* 在这里调用中断安全输出函数(实际函数
取决于正在使用的FreeRTOS端口)。*/
}
}
十二、xTimerResetFromISR()
API原型:
BaseType_t xTimerResetFromISR(
TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken);
可从中断服务例程调用的 xTimerReset() 的版本。
参数:
xTimer 待启动、重置或重启的定时器的句柄。
pxHigherPriorityTaskWoken 定时器服务/守护进程任务大部分时间 都处于阻塞状态,等待消息到达定时器 命令队列。 调用 xTimerResetFromISR() 将消息写入定时器 命令队列,从而让定时器服务/守护进程 任务有可能脱离阻塞状态。 如果调用 xTimerResetFromISR() 导致 定时器服务/守护进程任务脱离阻塞状态,且定时器服务/ 守护进程任务的优先级等于或大于当前执行的 任务(被中断的任务),那 *pxHigherPriorityTaskWoken 将在 xTimerResetFromISR() 函数内部被设置为 pdTRUE。 如果 xTimerResetFromISR() 将此值设置为 pdTRUE, 那应在中断退出前执行上下文切换。
返回值:
如果重置命令无法发送至定时器命令队列, 则将返回 pdFAIL。 如果命令成功发送至定时器命令队列, 则返回 pdPASS。 实际处理命令的时间 取决于定时器服务/守护进程任务相对于系统中其他任务的优先级, 尽管定时器到期时间 和实际调用 xTimerResetFromISR() 的时间相关。 定时器服务/守护进程 任务优先级由 configTIMER_TASK_PRIORITY 配置常量设置。
用法示例:
/* 本方案假设xBacklightTimer已经被创建。 当一个
键被按下时,LCD背光灯被打开。 如果5秒钟过去了
5秒后没有按键,LCD背光就会关闭。 在这种情况下
在这种情况下,定时器是一个一次性的定时器,与所给的例子不同的是
xTimerReset()函数的例子不同,按键事件处理程序是一个中断
服务例程。*/
/* 指派给一次性定时器的回调函数。 在这种情况下
参数不被使用。*/
void vBacklightTimerCallback( TimerHandle_t pxTimer )
{
/* 计时器过期了,因此在按下一个键之后,必须有5秒钟的时间。
计时器已经过期,因此必须在按下一个键之后过了5秒钟。 关闭LCD背光灯。*/
vSetBacklightState( BACKLIGHT_OFF );
}
/* 按键中断服务例程。*/
void vKeyPressEventInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* 确保LCD背光灯打开,然后重置负责关闭背光灯的定时器。
负责在5秒后关闭背光灯的计时器。
5秒后关闭背光。 这是一个中断服务例程,所以只能
调用以 "FromISR "结尾的FreeRTOS API函数。*/
vSetBacklightState( BACKLIGHT_ON );
/* 这里可以调用xTimerStartFromISR()或xTimerResetFromISR()。
因为两者都会导致定时器重新计算其到期时间。
xHigherPriorityTaskWoken在声明时被初始化为pdFALSE。
声明时被初始化为pdFALSE(在这个函数中)。*/
if( xTimerResetFromISR( xBacklightTimer,&xHigherPriorityTaskWoken ) != pdPASS )
{
/* 重置命令没有成功执行。 采取适当的
在这里采取适当的行动。*/
}
/* 在此执行其余的按键处理。*/
/* 如果xHigherPriorityTaskWoken等于pdTRUE,那么就应该进行上下文切换。
就应该执行上下文切换。 在ISR内部执行上下文切换所需的语法
所需的语法在不同的端口和不同的编译器中都有所不同。
编译器有所不同。 检查你正在使用的端口的演示,以找到
所需的实际语法。*/
if( xHigherPriorityTaskWoken != pdFALSE )
{
/* 在这里调用中断安全输出函数(实际函数
取决于正在使用的FreeRTOS端口)。*/
}
}
十三、pvTimerGetTimerID()
API原型:
void *pvTimerGetTimerID( TimerHandle_t xTimer );
返回分配给软件计时器的 ID。
使用调用 xTimerCreate() 时的 pvTimerID 参数将 ID 分配给定时器, 该函数用于创建定时器。
创建定时器时,会为定时器分配一个标识符 (ID), 您随时可以使用 vTimerSetTimerID() API 函数更改此 ID。
如果将同一个回调函数分配给多个定时器, 则可以在回调函数内检查定时器标识符, 以确定哪个定时器实际已到期。
在定时器回调函数的调用之间,定时器标识符也可用于将数据存储在定时器中 。
参数:
xTimer 被查询的定时器。
返回值:
分配给被查询的定时器的 ID。
十四、vTimerSetReloadMode()
API原型:
void vTimerSetReloadMode( TimerHandle_t xTimer,const UBaseType_t uxAutoReload );
将软件定时器的“模式”更新为自动重新加载定时器或一次性 定时器。
自动重新加载定时器每次过期都会自行重置,从而导致定时器 定期到期(并因此执行其回调)。
一次性定时器不会自动重置,因此除非手动重新启动, 否则只会过期一次(并因此执行其回调)。
此 API 函数仅在已构建项目中包含 FreeRTOS/Source/timers.c 源文件时 可用。
参数:
xTimer 要更新的定时器的句柄。 该句柄 将从对用于创建定时器的 xTimerCreate() 或 xTimerCreateStatic() 调用中返回。
uxAutoReload 将 uxAutoReload 设置为 pdTRUE 以将定时器设置为自动重新加载 模式,或设置为 pdFALSE 以将定时器设置为一次性模式。
十五、vTimerSetTimerID()
API原型:
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID );
创建定时器时,会为软件定时器分配一个标识符 (ID), 您可随时使用 vTimerSetTimerID() API 函数更改此标识符。
如果将同一个回调函数分配给多个定时器, 则可以在回调函数内检查定时器标识符, 以确定哪个定时器实际已到期。
在定时器回调函数的调用之间,定时器标识符也可用于将数据存储在定时器中 。
参数:
xTimer 更新的计时器。
pvNewID 句柄,定时器标识符将被设置为此句柄。
用法示例:
/* 一个分配给定时器的回调函数。*/
void TimerCallbackFunction( TimerHandle_t pxExpiredTimer )
{
uint32_t ulCallCount;
/* 这个定时器已经过期并执行其回调函数的次数。
并执行其回调函数的次数被存储在
定时器的ID中。 检索该计数,将其递增,然后保存到
检索该计数,将其递增,然后将其存回定时器的ID中。*/
ulCallCount = ( uint32_t ) pvTimerGetTimerID( pxExpiredTimer );
ulCallCount++。
vTimerSetTimerID( pxExpiredTimer, ( void * ) ulCallCount );
}
十六、xTimerGetTimerDaemonTaskHandle()
API原型:
TaskHandle_t xTimerGetTimerDaemonTaskHandle( void );
返回值:
返回与软件定时器守护进程(或服务)任务 关联的任务句柄。 如果在 FreeRTOSConfig.h 中将 configUSE_TIMERS 设置为 1, 则在启动 RTOS 调度器时会自动创建定时器守护进程任务。
十七、xTimerPendFunctionCall()
API原型:
BaseType_t xTimerPendFunctionCall(
PendedFunction_t xFunctionToPend,
void *pvParameter1,
uint32_t ulParameter2,
TickType_t xTicksToWait );
用于将函数的执行挂起到 RTOS 守护进程任务(定时器 服务任务,因此此函数前缀为“Timer”)。
可延迟到 RTOS 守护进程任务的函数必须具有以下 原型:
void vPendableFunction( void * pvParameter1, uint32_t ulParameter2 );
pvParameter1 和 ulParameter2 供 应用程序代码使用。
INCLUDE_xTimerPendFunctionCall() 和 configUSE_TIMERS 必须同时设置为 1,xTimerPendFunctionCall() 才可用。
参数:
xFunctionToPend 要从定时器服务/ 守护进程任务执行的函数。 函数必须符合上面所示的 PendedFunction_t 如上所示的 PendedFunction_t 原型。
pvParameter1 回调函数的第一个参数的值。 该参数为 void * 类型,可用于传递任何类型。 例如,整数类型可转换为 void *, 或者可使用 void * 指向结构体。
ulParameter2 回调函数的第二个参数的值。
xTicksToWait 调用此函数将导致 向队列中的定时器守护进程任务发送一条消息。 xTicksToWait 是指在队列已满的情况下,需要阻塞调用任务 (不使用任何处理时间)以等待定时器队列 释放可用空间的时间。 队列的长度由 FreeRTOSConfig.h 中的 configTIMER_QUEUE_LENGTH 值设置。
返回值:
如果消息成功发送到 RTOS 则返回 pdPASS,否则返回 pdFALSE。
十八、xTimerPendFunctionCallFromISR()
API原型:
BaseType_t xTimerPendFunctionCallFromISR(
PendedFunction_t xFunctionToPend,
void *pvParameter1,
uint32_t ulParameter2,
BaseType_t *pxHigherPriorityTaskWoken );
在应用程序中断服务程序中使用此函数, 用于将函数的执行推迟到 RTOS 守护进程任务(即定时器服务任务,因此该函数 在 timers.c 中实现,并以“Timer”为前缀)。
理想情况下,中断服务程序 (ISR) 需尽可能短, 但有时 ISR 要么需要处理很多任务, 要么需要执行非确定性任务。 在这些情况下,可使用 xTimerPendFunctionCallFromISR() 将 函数的处理推迟到 RTOS 守护进程任务。
这里提供了一种允许中断直接返回到 随后将执行挂起函数任务的机制。 使用该机制, 回调函数可在中断时间内连续执行, 就像回调在中断本身中执行一样。
可延迟到 RTOS 守护进程任务的函数必须具有以下 原型:
void vPendableFunction( void * pvParameter1, uint32_t ulParameter2 );
pvParameter1 和 ulParameter2 供 应用程序代码使用。
INCLUDE_xTimerPendFunctionCall() 和 configUSE_TIMERS 必须同时 设置为 1,xTimerPendFunctionCallFromISR() 才可用。
参数:
xFunctionToPend 要从定时器服务/ 守护进程任务执行的函数。 函数必须符合上面所示的 PendedFunction_t 如上所示的 PendedFunction_t 原型。
pvParameter1 回调函数的第一个参数的值。 该参数为 void * 类型,可用于传递任何类型。 例如,整数类型可转换为 void *, 或者可使用 void * 指向结构体。
ulParameter2 回调函数的第二个参数的值。
pxHigherPriorityTaskWoken 如上所述,调用 xTimerPendFunctionCallFromSR() 将意味着向 RTOS 定时器守护进程任务发送一条消息。 如果 守护进程任务的优先级(该任务 使用 configTIMER_TASK_PRIORITY 设置, 位于 FreeRTOSConfig.h 中)高于 当前正在运行的任务(中断中断的任务), 则需在 xTimerPendFunctionCallFromISR() 中 将 *pxHigherPriorityTaskWoken 设置为 pdTRUE, 表示应在中断退出之前请求上下文切换。 因此 必须将 *pxHigherPriorityTaskWoken 初始化为 pdFALSE。 请参阅 下面的代码示例。
返回值:
如果消息成功发送到 RTOS 定时器守护进程任务, 则返回 pdPASS,否则返回 pdFALSE。
用法示例:
/* 回调函数,将在守护任务的上下文中执行。
注意回调函数必须全部使用这个相同的原型。*/
void vProcessInterface( void *pvParameter1, uint32_t ulParameter2 )
{
BaseType_t xInterfaceToService;
/* 需要服务的接口在第二个参数中被传递。
参数中传递。 在这种情况下,第一个参数不被使用。*/
xInterfaceToService = ( BaseType_t ) ulParameter2;
/* ...在这里进行处理... */
}
/* 一个从多个接口接收数据包的ISR */
void vAnISR( void )
{
BaseType_t xInterfaceToService, xHigherPriorityTaskWoken;
/* 查询硬件以确定哪个接口需要处理。*/
xInterfaceToService = prvCheckInterfaces();
/* 实际的处理要推迟到一个任务。 要求在
vProcessInterface()回调函数被执行,传入需要处理的接口的编号。
需要处理的接口的编号。 需要服务的接口
服务的接口在第二个参数中被传递。 第一个参数
在这种情况下不使用。*/
xHigherPriorityTaskWoken = pdFALSE;
xTimerPendFunctionCallFromISR( vProcessInterface,
NULL,
( uint32_t ) xInterfaceToService,
xHigherPriorityTaskWoken);
/* 如果xHigherPriorityTaskWoken现在被设置为pdTRUE,那么就应该请求一个上下文切换。
则应请求进行上下文切换。 使用的宏是特定于端口的,将是
是portYIELD_FROM_ISR()或portEND_SWITCHING_ISR()--请参考所使用的端口的文档。
参考所使用端口的文档页面。*/
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
十九、pcTimerGetName()
API原型:
const char * pcTimerGetName( TimerHandle_t xTimer );
返回软件定时器的人类可读文本名称。
将文本名称分配给定时器需使用 调用 xTimerCreate() 函数的 pcTimerName 参数, 该函数用于创建定时器。
参数:
xTimer 被查询的定时器。
返回值:
指向定时器文本名称的指针,该指针为以 NULL 结尾的标准 C 字符串。
用法示例:
const char *pcTimerName = "ExampleTimer";
/* 一个创建定时器的函数。*/
static void prvCreateTimer( void )
{
TimerHandle_t xTimer;
/* 创建一个定时器。*/
xTimer = xTimerCreate( pcTimerName, /* Text name. */
pdMS_TO_TICKS( 500 ), /*周期。*/
pdTRUE, /* 自动加载。*/
NULL, /* 没有ID。*/
prvExampleCallback ); /*回调函数。*/
if( xTimer != NULL )
{
xTimerStart( xTimer, portMAX_DELAY );
/* 只是为了演示pcTimerGetName(),查询定时器的名称,如果不等于pcTimerGetName,则断言
如果它不等于pcTimerName则断言。*/
configASSERT( strcmp( pcTimerGetName( xTimer ), pcTimerName ) == 0 );
}
}
二十、xTimerGetPeriod()
API原型:
TickType_t xTimerGetPeriod( TimerHandle_t xTimer );
返回一个软件计时器的周期。 周期以滴答为单位。
初始时,一个定时器的周期由 用于创建定时器的 xTimerCreate() 函数的 xTimerPeriod 参数设置。 可以使用 xTimerChangePeriod() 和 xTimerChangePeriodFromISR() API 函数改变此周期。
参数:
xTimer 被查询的定时器。
返回值:
计时器的周期,以滴答为单位。
用法示例:
/* 一个分配给软件定时器的回调函数。*/
static void prvExampleTimerCallback( TimerHandle_t xTimer )
{
TickType_t xTimerPeriod;
/* 查询到期的定时器的周期。*/
xTimerPeriod = xTimerGetPeriod( xTimer );
}
二一、xTimerGetExpiryTime()
API原型:
TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer );
返回软件定时器到期的时间, 即执行定时器回调函数的时间。
如果 xTimerGetExpiryTime() 返回的值小于当前时间, 则定时器会在 tick 计数溢出并归 0 后到期。 计数溢出在 RTOS 实现中进行处理, 因此定时器的回调函数会在正确时间执行, 无论是在 tick 计数溢出之前还是之后。
参数:
xTimer 被查询的定时器。
返回值:
如果 xTimer 引用的定时器处于活动状态, 则返回定时器下一次到期的时间 (可能是在当前 tick 计数溢出之后, 请参阅上方注释)。
如果 xTimer 引用的定时器未处于活动状态, 则未定义返回值。
用法示例:
static void prvAFunction( TimerHandle_t xTimer )
{
TickType_t xRemainingTime;
/* 计算由xTimer引用的定时器到期前的剩余时间。
过期的时间。 TickType_t是一个无符号类型,所以即使计时器过期,减法也会得到正确的答案。
正确的答案,即使定时器在Tick_txt溢出后才会过期。
溢出。*/
xRemainingTime = xTimerGetExpiryTime( xTimer ) - xTaskGetTickCount( );
}
二二、xTimerGetReloadMode()、uxTimerGetReloadMode()
API原型:
BaseType_t xTimerGetReloadMode( TimerHandle_t xTimer );
UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer );
查询 xTimer 句柄引用的软件计时器的“模式”。
该模式可以是自动重载定时器(每次到期都会自动重置),或者 一次性计时器(除非手动重新启动,否则仅到期一次)。
xTimerGetReloadMode 和 uxTimerGetReloadMode 仅在其返回类型上有所不同。xTimerGetReloadMode 返回 BaseType_t 以匹配实际返回值 pdTRUE/pdFALSE 的类型。 uxTimerGetReloadMode 是为了向后兼容而提供的, 新的应用程序应该使用 xTimerGetReloadMode 来代替。
这些 API 函数仅在已构建项目中包含 FreeRTOS ‘timers.c’ 源文件, 并且在 FreeRTOSConfig.h 中将 configUSE_TIMERS 设置为 1 时才可用。
参数:
xTimer 要查询的定时器的句柄。该句柄通过调用用于创建计时器的 xTimerCreate() 或 xTimerCreateStatic() 返回。
返回值:
如果句柄为 xTimer 的定时器为自动重载定时器,则返回 pdTRUE,否则返回 pdFALSE。
二三、软件定时器示例
/**
* @file 11_SoftwareTimer.c
* @author WSP
* @brief 软件定时器 不受定时器个数限制
* @version 0.1
* @date 2022-10-18
*
* @copyright Copyright (c) 2022
*
*/
#include "FreeRTOS_Include.h"
const static char *TAG = "APP_SoftwareTimer";
#define USER_AUTORELOAD 1 // 0的时候不开启定时器自动重装载 1开启启定时器自动重装载
#define USER_TIMER_SAME_CALLBACK
// #define USER_SET_TIMER_PERIOD
// #define USER_TIMER_DELETE
// #define REST_TIME2
void Timer1_callback(TimerHandle_t xTimer)
{
static int Timer_count = 0;
if(strcmp(pcTimerGetName(xTimer),"Timer1") == 0){ // 定时器1的传入ID方式和定时器2的不同,处理方法不同
int * Timer_ID;
Timer_ID = (int *) pvTimerGetTimerID(xTimer);
ESP_LOGI(TAG, "Timer name is Timer1, timer id is %d callback count:%d", * Timer_ID,Timer_count);
}else{
ESP_LOGI(TAG, "Timer name is %s, timer id is %d callback count:%d",pcTimerGetName(xTimer), (uint32_t)pvTimerGetTimerID(xTimer),Timer_count);
}
Timer_count ++;
}
/**
* @brief 创建函数初始化
* @param NULL
* @return NULL
*/
void SoftwareTimer_Init(void)
{
TimerHandle_t xTimer1;
int Timer1_ID = 1;
xTimer1 = xTimerCreate("Timer1", // 定时器名字
pdMS_TO_TICKS(1000), // 定时器周期
#if USER_AUTORELOAD
pdTRUE, // 自动重装载
#else
pdFALSE, // 不自动重装载
#endif
(void *)&Timer1_ID, // TImer ID
Timer1_callback); // 定时器回调函数
#ifdef USER_TIMER_SAME_CALLBACK
TimerHandle_t xTimer2;
xTimer2 = xTimerCreate("Timer2", // 定时器名字
pdMS_TO_TICKS(2000), // 定时器周期
#if USER_AUTORELOAD
pdTRUE, // 自动重装载
#else
pdFALSE, // 不自动重装载
#endif
(void *)2, // TImer ID
Timer1_callback); // 定时器回调函数
xTimerStart(xTimer2, 0); // 开始定时器 等待0ms开启时间器
#endif
xTimerStart(xTimer1, 0); // 开始定时器 等待0ms开启时间器
vTaskDelay(10000 / portTICK_PERIOD_MS); // 延时等待
#ifdef USER_TIMER_DELETE
xTimerDelete(xTimer1,0); // 删除定时器1
xTimerDelete(xTimer2,0); // 删除定时器2
ESP_LOGI(TAG,"The timer is deleted");
#endif
#ifdef USER_SET_TIMER_PERIOD
xTimerChangePeriod(xTimer1,pdMS_TO_TICKS(4000),0);
#endif
while (1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS); // 延时等待
#ifdef REST_TIME2
xTimerReset(xTimer2,0); // 模拟看门狗,直接给软件定时器复位
#endif
}
}