SIEMENS山东省潍坊市 西门子代理商——西门子华北一级总代理
| 更新时间 2024-11-16 07:00:00 价格 请来电询价 西门子总代理 PLC 西门子一级代 驱动 西门子代理商 伺服电机 联系电话 15903418770 联系手机 15915421161 联系人 张经理 立即询价 |
详细介绍
2.6 软件定时器任务基本功能(三部分)
/* Just to avoid compiler warnings. */ ( void ) pvParameters;
#if( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 ) ...略去部分代码 #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */
for( ;; ){ /* 获取Zui近一次定时器超时时间 */ xNextExpireTime = prvGetNextExpireTime(&xListWasEmpty); /* 处理超时的定时器或者让队列阻塞 */ prvProcessTimerOrBlockTask(xNextExpireTime, xListWasEmpty); /* 处理队列接收到的命令 */ prvProcessReceivedCommands();}}
/* 判断当前定时器列表是否为空 */ *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList ); /* 当前列表非空 */ if( *pxListWasEmpty == pdFALSE ){ /* 获取Zui近超时时间 */ xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );} else /* 当前列表为空 */{ /*超时时间设为0,使任务非阻塞 */ xNextExpireTime = ( TickType_t ) 0U;}
return xNextExpireTime;}3.2 处理或阻塞软件定时器任务
/* 挂起调度器 */ 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 ); }
/* 定时器定时时间还没到,将当前任务挂起,让队列按照给定的时间进行阻塞 */ vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty ); /* 解除调度器挂起 */ if( xTaskResumeAll() == pdFALSE ) { /* 申请切换任务 */ portYIELD_WITHIN_API(); } else { mtCOVERAGE_TEST_MARKER(); } } } else { /* 解除调度器挂起 */ ( void ) xTaskResumeAll(); } }}
软件定时器任务的具体内容可分为三部分:
获取Zui近一次定时器超时时间
处理超时的定时器或者让队列阻塞
处理队列接收到的命令
三部分不断循环处理实现Daemon任务。
/* Just to avoid compiler warnings. */ ( void ) pvParameters;
#if( configUSE_DAEMON_TASK_STARTUP_HOOK == 1 ) ...略去部分代码 #endif /* configUSE_DAEMON_TASK_STARTUP_HOOK */
for( ;; ){ /* 获取Zui近一次定时器超时时间 */ xNextExpireTime = prvGetNextExpireTime(&xListWasEmpty); /* 处理超时的定时器或者让队列阻塞 */ prvProcessTimerOrBlockTask(xNextExpireTime, xListWasEmpty); /* 处理队列接收到的命令 */ prvProcessReceivedCommands();}}
以上介绍了从启动调度器到实现Daemon任务的具体过程,下面来详细分析Daemon任务中的三部分功能的细节。
3 软件定时器任务功能分析
先来一张整体结构图:
首先是从定时器列表中获取下一次的溢出时间,因为各定时器的溢出时间是按照升序排列的,因此只需获取下一次的溢出时间。
3.1 获取下一个定时超时时间/* 判断当前定时器列表是否为空 */ *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList ); /* 当前列表非空 */ if( *pxListWasEmpty == pdFALSE ){ /* 获取Zui近超时时间 */ xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );} else /* 当前列表为空 */{ /*超时时间设为0,使任务非阻塞 */ xNextExpireTime = ( TickType_t ) 0U;}
return xNextExpireTime;}3.2 处理或阻塞软件定时器任务
那系统如何处理软件定时器列表?系统在不断运行,而xTimeNow(xTickCount)随着SysTick的触发一直在增长,在软件定时器任务运行的时候会获取下一个要唤醒的定时器:
比较当前系统时间xTimeNow是否大于或等于下一个定时器唤醒时间xTicksToWait
若大于则表示已经超时,定时器任务将会调用对应定时器的回调函数
否则将软件定时器任务挂起,直至下一个要唤醒的软件定时器时间到来或者接收到命令消息
/* 挂起调度器 */ 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 ); }
/* 定时器定时时间还没到,将当前任务挂起,让队列按照给定的时间进行阻塞 */ vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty ); /* 解除调度器挂起 */ if( xTaskResumeAll() == pdFALSE ) { /* 申请切换任务 */ portYIELD_WITHIN_API(); } else { mtCOVERAGE_TEST_MARKER(); } } } else { /* 解除调度器挂起 */ ( void ) xTaskResumeAll(); } }}
相关产品