成功申请定时器后, 定时器并没有开始工作, 需要调用函数将该定时器中的 xTimerListItem 插入到定时器管理链表中, Daemon 任务才能在该定时器设定的溢出时刻调用其回调函数。
timers.c 中定义了如下几个链表变量用于管理定时器, 定时器根据其溢出时刻从小到大插入链表进行管理。
使用两个链表是为了应对系统 TickCount 溢出的问题,在 FreeRTOS 任务调度 系统节拍 介绍过。
PRIVILEGED_DATA static List_t xActiveTimerList1;
PRIVILEGED_DATA static List_t xActiveTimerList2;
// 当前节拍计数器对应的定时器管理链表指针
PRIVILEGED_DATA static List_t *pxCurrentTimerList;
// 溢出时间到了下一个节拍计数阶段(当前节拍计数器溢出后)的定时器管理链表指针
PRIVILEGED_DATA static List_t *pxOverflowTimerList;
文章开头提到的使用定时器的函数, 大部分都带有一个参数,用于设置调用后允许阻塞的最大时间, 原因是, 这些函数并没有直接操作定时器管理链表, 而是向定时器Daemon 任务的消息队列 xTimerQueue 发送消息命令。 之后, 定时器Daemon 任务会从消息队列取出消息并响应操作。
此处,从系统启动的定时器Daemon 任务展开分析 FreeRTOS 的软定时器的实现 。

该任务主体的执行流程如下所示 :

永久循环部分的代码 :
for( ;; )
{
// 读取定时器队列第一个链表项的值 -> 即将溢出的定时器时间(ticks)
// 如果链表空, 返回的是 0
xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
// 处理溢出的定时器
// 阻塞直到下一个定时器溢出 或 消息队列有新命令
prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
// 读取消息队列,执行命令
prvProcessReceivedCommands();
}
定时器任务中, 取出下一个定时器溢出的时间,并把它传递给函数prvProcessTimerOrBlockTask, 该函数负责处理溢出定时器, 应对节拍计数器溢出问题等, 并设置合适的时间阻塞 Daemon 任务, 让出 CPU 使用权直到下一个定时器溢出或者接收到新的命令。
static void prvProcessTimerOrBlockTask(
const TickType_t xNextExpireTime,
BaseType_t xListWasEmpty )
{
TickType_t xTimeNow;
BaseType_t xTimerListsWereSwitched;
// 挂起调度器 避免任务切换
vTaskSuspendAll();
{
// 判断系统节拍计数是否溢出
// 如果是,处理溢出定时器, 并切换定时器链表
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
// 系统节拍计数器没有溢出
if( xTimerListsWereSwitched == pdFALSE )
{
// 判断是否有定时器溢出
if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
{
// 恢复调度
( void ) xTaskResumeAll();
//执行相应定时器的回调函数
// 对于需要自动重载的定时器, 更新下一次溢出时间, 插回链表
prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
}
else
{
// 当前链表没有定时器
if( xListWasEmpty != pdFALSE )
{
// 判断溢出链表上是否有定时器
xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );
}
// 阻塞挂起直到 : 下一个定时器溢出 或 新命令消息
// 下面这个queue函数是内核专用, 调用后不会直接阻塞,但是会把任务加入到阻塞链表中
vQueueWaitForMessageRestricted( xTimerQueue,
( xNextExpireTime - xTimeNow ), /*转换阻塞时间*/
xListWasEmpty );
if( xTaskResumeAll() == pdFALSE )
{
// 触发任务切换
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
else
{
// 恢复调度
( void ) xTaskResumeAll();
}
}
}
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-29404-3.html
台湾的民进党是汉奸党