FreeRTOS的Delay函数

两个Delay函数

有两个延时函数

  • vTaskDelay:至少等待指定个数的Tick Interrupt才能变为就绪态

  • xTaskDelayUtil:等待到指定的绝对时刻,才能变为就绪态

个人感觉这两个延时函数就是,比如一个我等3个小时,一个是我等到下午3点的区别。

两个函数的原型如下:

vTaskDelay:

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();

                /* A task that is removed from the event list while the
                 * scheduler is suspended will not get placed in the ready
                 * list or removed from the blocked list until the scheduler
                 * is resumed.
                 *
                 * This task cannot be in an event list as it is the currently
                 * executing task. */
                prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
            }
            xAlreadyYielded = xTaskResumeAll();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* Force a reschedule if xTaskResumeAll has not already done so, we may
         * have put ourselves to sleep. */
        if( xAlreadyYielded == pdFALSE )
        {
            portYIELD_WITHIN_API();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

xTaskDelayUtil

 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();
        {
            /* Minor optimisation.  The tick count cannot change in this
             * block. */
            const TickType_t xConstTickCount = xTickCount;

            /* Generate the tick time at which the task wants to wake. */
            xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;

            if( xConstTickCount < *pxPreviousWakeTime )
            {
                /* The tick count has overflowed since this function was
                 * lasted called.  In this case the only time we should ever
                 * actually delay is if the wake time has also  overflowed,
                 * and the wake time is greater than the tick time.  When this
                 * is the case it is as if neither time had overflowed. */
                if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
                {
                    xShouldDelay = pdTRUE;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                /* The tick time has not overflowed.  In this case we will
                 * delay if either the wake time has overflowed, and/or the
                 * tick time is less than the wake time. */
                if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
                {
                    xShouldDelay = pdTRUE;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }

            /* Update the wake time ready for the next call. */
            *pxPreviousWakeTime = xTimeToWake;

            if( xShouldDelay != pdFALSE )
            {
                traceTASK_DELAY_UNTIL( xTimeToWake );

                /* prvAddCurrentTaskToDelayedList() needs the block time, not
                 * the time to wake, so subtract the current tick count. */
                prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        xAlreadyYielded = xTaskResumeAll();

        /* Force a reschedule if xTaskResumeAll has not already done so, we may
         * have put ourselves to sleep. */
        if( xAlreadyYielded == pdFALSE )
        {
            portYIELD_WITHIN_API();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        return xShouldDelay;
    }

下面是图示:

  • 使用vTaskDelay(n)时,进入,退出vTaskDelay的时间间隔至少是n个Tick中断

  • 使用xTaskDelayUtil(&Pre,n)时,前后两次退出xTaskDelayUntil的时间至少是n个Tick中断

  • 退出xTaskDelayUntil时任务就进入就绪态,一般都能得到执行机会

  • 所以可以使用xTaskDelayUntil来让任务周期性的运行

实验证明

程序创建2个任务

  • Task1:

  • 高优先级

  • 设置变量flag为1,然后调用vTaskDelay(xDelay50ms)或vTaskDelayUntil(&xLastWakeTime,xDelay50ms)

  • Task2:

  • 低优先级

  • 设置变量flag=0

main函数代码如下:

int main(void)
{
    prvSetupHardware();

    /*Task1的优先级更高,Task1先执行*/
    xTaskCreate(vTask1,"Task1",1000,NULL,2,NULL);
    xTaskCreate(vTask2,"Task2",1000,NULL,1,NULL);

    /*启动调度器*/
    vTaskStartScheduler();

    /*如果程序运行到这里,就表示出错了,一般是内存不足*/
    return 0;


}

Task1的代码中使用条件开关来选择Delay函数,把#if 1 改为 #if 0 就可以使用vTaskDelayUntil,代码如下:

void vTask1(void *pvParameters)
{
    const TickType_t xDelay50ms = pdMS_TO_TICKS(50UL);
    TickType_t xLastWakeTime;
    int i;
    /*获得当前的Tick Count*/
    xLastWakeTime = xTaskGetTickCount();
    
    for(;;)
    {
        flag =1;
        /*故意加入多个循环,让程序运行时间长一点*/
        for(i=0;i<5;i++)
            printf("Task1 is running\r\n");
#if 1
        vTaskDelay(xDelay50ms);
#else 
        vTaskDelayUntil(&PreWakeTime,xDelay50ms);
    }
}

使用MDK的逻辑分析仪,可以观察flag变量的bit波形,如下:

  • flag为1时表示,Task1正在运行,flag为0时表示Task2正在运行,也就是Task1处于阻塞状态

  • vTaskDelay:指定的是阻塞时间

  • vTaskDelayUntil:指定的是任务执行的间隔,周期

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值