延时函数

vTaskDelay()

相对延时函数,在文件task.c中定义的,要使用的话宏INCLUDE_vTaskDelay必须设置为1;

void vTaskDelay( const TickType_t xTicksToDelay )
{
BaseType_t xAlreadyYielded = pdFALSE; /* A delay time of zero just forces a reschedule. */
if( xTicksToDelay > ( TickType_t ) 0U )
{
configASSERT( uxSchedulerSuspended == 0 );
vTaskSuspendAll();
{
traceTASK_DELAY();
prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
}
xAlreadyYielded = xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
} if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
  • 延时参数xTicksToDelay为要延时的时间节拍数,肯定要大于0,否则相当于直接调用函数portYIELD()进行任务切换;
  • 调用vTaskSuspendAll()挂起任务调度器;
  • 调用函数prvAddCurrentTaskToDelayedList()将要延时的任务添加到延时列表中;
  • 调用xTaskResumeAll()恢复任务调度器,并在之后检测xTaskResumeAll()返回参数,如果没进行任务调度的话,那么调用portYIELD_WITHIN_API()进行任务调度;

函数prvAddCurrentTaskToDelayedList()分析

static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, const BaseType_t xCanBlockIndefinitely )
{
TickType_t xTimeToWake;
const TickType_t xConstTickCount = xTickCount; #if( INCLUDE_xTaskAbortDelay == 1 )
{
pxCurrentTCB->ucDelayAborted = pdFALSE;
}
#endif if( uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
} #if ( INCLUDE_vTaskSuspend == 1 )
{
if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) )
{
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
xTimeToWake = xConstTickCount + xTicksToWait;
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
if( xTimeToWake < xConstTickCount )
{
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
if( xTimeToWake < xNextTaskUnblockTime )
{
xNextTaskUnblockTime = xTimeToWake;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
}
#else /* INCLUDE_vTaskSuspend */
{
xTimeToWake = xConstTickCount + xTicksToWait;
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake ); if( xTimeToWake < xConstTickCount )
{
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
if( xTimeToWake < xNextTaskUnblockTime )
{
xNextTaskUnblockTime = xTimeToWake;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
} ( void ) xCanBlockIndefinitely;
}
#endif /* INCLUDE_vTaskSuspend */
}
  • 读取进入该函数的时间点并保存在xConstTickCount中,后面在计算唤醒时间点的时候要用到,xTickCount是时钟节拍计数器,每个滴答定时器中断xTickCount都会加一
  • 将当前任务从就绪表中移除;
  • 取消当前任务在uxTopReadyPriority中的就绪标记,即将相应的bit清0;
  • 如果延时时间为最大值portMAX_DELAY并且xCanBlockIndefinitely不为pdFALSE(即表示允许阻塞任务),那么直接将当前任务添加到挂起列表中,任务就不用添加到延时列表中了;
  • 计算唤醒的时间点,之后将唤醒时间点值写入到任务列表中状态列表项的相应字段中;
  • 如果计算得到的唤醒时间点小于xConstTickCount说明发生了溢出,FreeRTOS针对此现象专门做了处理,定义了两个延时列表xDelayedTaskList1和xDelayedTaskList2,也定义了两个指针pxDelayedTaskList和pxOverflowDelayedTaskList来访问这两个列表,在初始化列表函数中分别进行了初始化;
  • xNextTaskUnblockTime是个全局变量,保存着距离下一个要取消阻塞的任务最小时间点值,当计算的唤醒时间点xTimeToWake小于xNextTaskUnblockTime,就更新替换;

vTaskDelayUntil()

绝对延时函数,该函数会阻塞任务,阻塞时间是一个绝对时间,如果是一些需要按照一定的频率运行的任务可以使用该函数;

函数定义如下:

void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )
  • pxPreviousWakeTime,上一次任务延时结束被唤醒的时间点,任务中第一次调用该函数时需要将pxPreviousWakeTime初始化进任务的while()循环体的时间点值,之后的运行中该函数会自动更新pxPreviousWakeTime的值;
  • xTimeIncrement,任务需要延时的时间节拍数;

使用模板如下:

void test_task(void *pvParameters)
{
TickType_t PreviousWakeTime; //延时50ms,将延时时间转换成节拍数
const TickType_t TimeIncrement = pdMS_TO_TICKS(50);
PreviousWakeTime = xTaskGetTickCount(); //获取当前的系统节拍值
for( ; ; )
{
/* 任务主体 */ /* 调用延时函数 */
vTaskDelayUntil(&PreviousWakeTime, TimeIncrement);
}
}

注意:使用函数vTaskDelayUntil()延时的任务也不一定就能周期性的运行,只能保证按照一定的周期取消阻塞,进入就绪态,如果有更高优先级或者中断的话,还是要等待其他更高优先级任务或者中断服务函数运行完成后才能运行;

最新文章

  1. Java Graphics2D 画出文字描边效果
  2. Java泛型学习笔记 - (二)泛型类
  3. CLRS:master theory in complexity of algorithm
  4. VisualVM 监控
  5. Codeforces 55D Beautiful Number
  6. ios开发相关网站
  7. 13. vs2010 ClientID bug处理
  8. 去掉所有的html标签
  9. sql设置事务隔离级别
  10. html中编写js的方式
  11. Egret的项目结构
  12. 【POJ】 1061 青蛙的约会(扩欧)
  13. 利用layer实现MVC页面数据互交提示弹框
  14. MySQL性能调优与架构设计
  15. 【Unity3D与23种设计模式】桥接模式(Bridge)
  16. python学习之路网络编程篇(第五篇)
  17. 【输入法】Rime-中州韵 基本设置 附:官方定制指南
  18. Python 使用sqlalchemy操作MYSQL
  19. 【转】Android随笔之——PackageManager详解
  20. Hyperledger Fabric(v1.2.0)代码分析1——channel创建

热门文章

  1. PHP爬虫最全总结2-phpQuery,PHPcrawer,snoopy框架中文介绍
  2. HTML中,a href =&quot; &quot;和 a href =&quot;#&quot;的区别
  3. java日志框架系列(9):logback框架过滤器(filter)详解
  4. java虚拟机栈(关于java虚拟机内存的那些事)
  5. 第7章学习小结 不使用STL-map过实践题:QQ帐户的申请与登陆
  6. 前端通过js获取手机型号
  7. python学习-39 生成器总结
  8. 笔记-8:mysql触发器
  9. 1192: 零起点学算法99——The sum problem(C)
  10. C#基础算法题 找出最大值和最小值