使能软件定时器功能:
添加 timer.c 和 timer.h 文件
添加配置
#define configUSE_TIMERS 1创建定时器
// 动态创建定时器
TimerHandle_t xTimerCreate(const char * const pcTimerName, // 定时器名字
const TickType_t xTimerPeriodInTicks, // 定时时间,单位为系统节拍
const UBaseType_t uxAutoReload, // pdTRUE 自动重装载;pdFALSE 一次性
void * const pvTimerID, // 定时器ID,这个用于回调函数区分是哪个定时器
TimerCallbackFunction_t pxCallbackFunction); // 回调函数删除定时器
BaseType_t xTimerDelete( TimerHandle_t xTimer, // 定时器句柄
TickType_t xTicksToWait ); // 超时时间删除定时器并不是由 xTimerDelete 这个函数删除的,它只是向定时器任务发送了一个删除命令,定时器任务会真正删除掉该定时器。
超时原因:
系统负载高,定时器任务优先级低,得不到调度。
定时器任务的命令队列已满,规定时间内来不及删除。
开/关定时器
开启定时器
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
BaseType_t xTimerStartFromISR(TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken);关闭定时器
BaseType_t xTimerStop(TimerHandle_t xTimer, TickType_t xTicksToWait);
BaseType_t xTimerStopFromISR(TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken);修改定时周期
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,
TickType_t xNewPeriod, // 定时时间
TickType_t xTicksToWait ); // 超时时间
BaseType_t xTimerChangePeriodFromISR(TimerHandle_t xTimer,
TickType_t xNewPeriod,
BaseType_t *pxHigherPriorityTaskWoken);定时器复位
如果定时器已经在运行,会把它的倒计时重置为初始值;如果它是停止状态,会把它启动。
BaseType_t xTimerReset(TimerHandle_t xTimer,
TickType_t xTicksToWait);返回结果:
pdFAIL:操作失败,已超时
pdPASS:操作成功
中断安全函数:
BaseType_t xTimerResetFromISR(TimerHandle_t xTimer,
BaseType_t *pxHigherPriorityTaskWoken);示例:
void My_ISR_Handler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// 重置定时器
xTimerResetFromISR(myTimerHandle, &xHigherPriorityTaskWoken);
// 通知内核是否要立即切换上下文
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}pxHigherPriorityTaskWoken这个参数,FreeRTOS告诉你,在执行定时器复位后,是否有高优先级的任务被唤醒。
疑惑:
既然 xTimerResetFromISR() 里都知道是否唤醒了高优先级任务,为啥不自己切换上下文,非得我去调 portYIELD_FROM_ISR()?
答:
这是FreeRTOS的设计思想,故意不自动切换上下文,而是将切换上下文的控制权交给用户,可以使程序更加灵活。
很多FromISR 函数都可能会发生高优先级的任务被唤醒,如果每次都自动切换了上下文,会导致效率变低。
比如这样写代码,最后再切换任务:
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(queue1, &data1, &xHigherPriorityTaskWoken);
xQueueSendFromISR(queue2, &data2, &xHigherPriorityTaskWoken);
xTimerResetFromISR(timer, &xHigherPriorityTaskWoken);
...
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);FromISR 函数中对是否切换标志的处理逻辑如下,不会覆盖之前的 pdTRUE,可放心使用。
if (唤醒了更高优先级任务)
{
*pxHigherPriorityTaskWoken |= pdTRUE; // 逻辑或,不会覆盖之前的 pdTRUE
}