上面提到, 通过函数 prvSampleTimeNow判断节拍计数器是否发发生溢出, 并执行相应处理, 此处看看该函数内容 :
static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )
{
TickType_t xTimeNow;
// 静态变量 记录上一次调用时系统节拍值
PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U;
// 获取本次调用节拍结束器值
xTimeNow = xTaskGetTickCount();
// 判断节拍计数器是否溢出过
// 比如 8bit : 0xFF+1 -> 0
if( xTimeNow < xLastTime )
{
// 发生溢出, 处理当前链表上所有定时器并切换管理链表
prvSwitchTimerLists();
*pxTimerListsWereSwitched = pdTRUE;
}
else
{
*pxTimerListsWereSwitched = pdFALSE;
}
// 更新记录
xLastTime = xTimeNow;
return xTimeNow;
}
可以看到, 该函数每次调用都会记录节拍值, 下一次调用,通过比较相邻两次调用的值判断节拍计数器是否溢出过。
当节拍计数器溢出, 需要处理掉当前链表上的定时器(应为这条链表上的定时器都已经溢出了), 然后切换链表。
对于处理这部分任务的函数, 主要要注意其对于需要重载的定时器的处理 :
类比一下 , 一个自动重载的定时器, 每月需要执行一次, 上次调用是2016 年6月, 之后由于优先级问题,导致下一次调用时间等到第二年2017年 1月了,也就是跨年了(节拍计数器溢出了), 切换日历(链表)前, 需要把旧的先处理掉, 那么实际该定时器在2016年 7~ 12月每月都需要执行一次,所以要补偿回来,直到第二年1月, 才发送消息,插到新日历里面(链表)。
即使时间延迟了,但是该调用几次,是保证的!!
static void prvSwitchTimerLists( void )
{
TickType_t xNextExpireTime, xReloadTime;
List_t *pxTemp;
Timer_t *pxTimer;
BaseType_t xResult;
// 切换链表前, 需要先处理当前链表上的所有执行定时器
while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
{
// 获取第一个定时器溢出时间
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
// 取出定时器并从链表移除
pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
traceTIMER_EXPIRED( pxTimer );
// 执行定时器回调函数
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
// 对于自动重载的定时器 计算下一次溢出时间
if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )
{
// 如果重载后定时器的时间没有溢出, 还在当前链表范围内, 继续插回到当前链表
// 保证执行的次数
xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
if( xReloadTime > xNextExpireTime )
{
// 设置下一次溢出时间
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
}
else
{
// 重载后定时器的时间同节拍计数器一样溢出了
// 需要插入到新的链表中, 通过消息发送
// 等到处理消息时,链表已经切换了
xResult = xTimerGenericCommand(
pxTimer,
tmrCOMMAND_START_DONT_TRACE,
xNextExpireTime,
NULL,
tmrNO_DELAY );
configASSERT( xResult );
( void ) xResult;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
// 切换链表
pxTemp = pxCurrentTimerList;
pxCurrentTimerList = pxOverflowTimerList;
pxOverflowTimerList = pxTemp;
}
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-29404-4.html
美国伟大的国家
公关出力了