FreeRTOS 时间管理

延时函数介绍

函数

描述

vTaskDelay()

相对延时

xTaskDelayUntil()

绝对延时

相对延时:指每次延时都是从执行函数vTaskDelay()开始,直到延时指定的时间结束 

绝对延时:指将整个任务的运行周期看成一个整体,适用于需要按照一定频率运行的任务 

  1. 为任务主体,也就是任务真正要做的工作
  2. 是任务函数中调用vTaskDelayUntil()对任务进行延时
  3. 为其他任务在运行 

vTaskDelay()

     函数 vTaskDelay() 用于对任务进行延时,延时的时间单位为系统时钟节拍,使用函数,需要的 FreeRTOSConfig.h 文件中将配置项 INCLUDE_vTaskDelay 配置为 1。
void vTaskDelay(const TickType_t xTicksToDelay); 

        函数用于使任务进入阻塞状态,以实现延时功能。延时的时间以 FreeRTOS 的时钟节拍为单位。 指每次延时都是从执行函数 vTaskDelay() 开始,直到延时指定的时间(参数:滴答值)结束。 

        参数 xTicksToDelay 用于设置延迟的时钟节拍个数,范围 1- 0xFFFFFFFF。 

        在使用此函数进行任务延时时,如果传入的参数为 0,那表明不进行任务延时,而是强
制进行一次任务切换。
void vTaskDelay( const TickType_t xTicksToDelay )
{
     BaseType_t xAlreadyYielded = pdFALSE;
    /* 只有在延时时间大于 0 的时候,才需要进行任务阻塞,
     * 否则相当于强制进行任务切换,而不阻塞任务*/
     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();
     }
}

xTaskDelayUntil()

        函数 xTaskDelayUntil() 用于对任务进行绝对延时,延时的时间单位为系统时钟节拍,使用需要在 FreeRTOSConfig.h 文件中将配置项 INCLUDE_vTaskDelayUntil 配置为 1。 

BaseType_t xTaskDelayUntil( TickType_t * const  pxPreviousWakeTime,
                            const TickType_t    xTimeIncrement   );

         函数描述:函数 vTaskDelayUntil 用于周期性延迟。 属于绝对延时,指间隔指定的时间(参数:滴答值),执行一次调用 vTaskDelayUntil() 函数的任务。

参数说明
pxPreviousWakeTime存储任务最后一次解除阻塞的时间
xTimeIncrement周期性延迟时间
返回值BaseType_t
pdTRUE操作成功
pdFALSE操作失败
#if ( INCLUDE_xTaskDelayUntil == 1 )
BaseType_t xTaskDelayUntil(TickType_t * const  pxPreviousWakeTime, /*上一次阻塞超时时间*/
                           const TickType_t    xTimeIncrement    ) /*延时的时间*/
{
     TickType_t xTimeToWake;
     BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
 
     configASSERT( pxPreviousWakeTime );
     configASSERT( ( xTimeIncrement > 0U ) );
     configASSERT( uxSchedulerSuspended == 0 );
 
     /* 挂起任务调度器 */
     vTaskSuspendAll();
     {
         const TickType_t xConstTickCount = xTickCount;
 
         /* 计算任务下一次阻塞超时的时间,
          * 这个阻塞超时时间是相对于上一次阻塞超时的时间的*/
         xTimeToWake = *pxPreviousWakeTime + xTimeIncrement
         /* 如果在上一次阻塞超时后,
          * 系统时钟节拍计数器溢出过*/
         if( xConstTickCount < *pxPreviousWakeTime )
         {
             /* 只有在下一次阻塞超时时间也溢出,
              * 并且下一次阻塞超时时间大于系统时钟节拍计数器的值时,
              * 需要做相应的溢出处理,否则就好像没有溢出*/
             if( ( xTimeToWake < *pxPreviousWakeTime ) &&( xTimeToWake > xConstTickCount ) )
             {
                 xShouldDelay = pdTRUE;/* 标记因为溢出,需要做相应的处理 */
             }
             else
             {
                 mtCOVERAGE_TEST_MARKER();
             }
         }
         else
         {
             /* 系统时钟节拍计数器没有溢出,
              * 但是下一次阻塞超时时间溢出了,
              * 并且下一次阻塞超时时间大于系统时钟节拍计数器的值时,
              * 需要做相应的溢出处理*/
             if( ( xTimeToWake < *pxPreviousWakeTime ) ||( xTimeToWake > xConstTickCount ) )
             {             
                 xShouldDelay = pdTRUE; /* 标记因为溢出,需要做相应的溢出处理 */
             }
             else
             {
                 mtCOVERAGE_TEST_MARKER();
             }
         }
 
         /* 更新上一次阻塞超时时间为下一次阻塞超时时间 */
         *pxPreviousWakeTime = xTimeToWake;
 
         /* 根据标记,做相应的溢出处理 */
         if( xShouldDelay != pdFALSE )
         {
             /* 用于调试,不用理会 */
             traceTASK_DELAY_UNTIL( xTimeToWake );
 
             /* 将任务添加到阻塞态任务列表中 */
             prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount,pdFALSE );
         }
         else
         {
             mtCOVERAGE_TEST_MARKER();
         }
     }
     /* 恢复任务调度器运行,
      * 调用此函数会返回是否需要进行任务切换*/
     xAlreadyYielded = xTaskResumeAll();
 
     /* 根据标志进行任务切换 */
     if( xAlreadyYielded == pdFALSE )
     {
         portYIELD_WITHIN_API();
     }
    else
     {
         mtCOVERAGE_TEST_MARKER();
     } 
     return xShouldDelay;
}
#endif /* INCLUDE_xTaskDelayUntil */

不知道你们有没有想过为什么是 xTaskDelayUntil() 而不是 vTaskDelayUntil(),我在tasks.c文件中找到

延时函数演示实验

学习 FreeRTOS 相对延时和绝对延时API 函数的使用,并了解其区别

实验设计:

将设计三个任务:start_task、task1、task2 

三个任务的功能如下:

  • start_task:用来创建其他的2个任务
  • task1:用于展示相对延时函数vTaskDelay ( )的使用
  • task2:用于展示绝对延时函数vTaskDelayUntil( )的使用

 其他部分代码如有需要可参考上一篇博文

 FreeRTOS 任务相关API函数

//用于展示相对延时函数vTaskDelay ( )的使用
void task1(void * pvParameters)
{
	
	while(1)
	{
		
		LED0_TOGGLE();
		delay_ms(10);
		vTaskDelay(500);
	}
	
}

 
//用于展示绝对延时函数vTaskDelayUntil( )的使用
void task2(void * pvParameters)
{
	TickType_t xLastWakeTime = xTaskGetTickCount();

	while(1)
	{
		
		LED1_TOGGLE();	
		delay_ms(10);
		xTaskDelayUntil(&xLastWakeTime,500);
		
	}
}
 

 现象

注意:

可能会出现任务一在延时时,任务2在运行,但是在任务1解除延时时候任务2刚好在死延时,因为优先级原因所以任务1运行不了代表任务1不止延时了510ms。

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值