FreeRTOS官方文件分析(四)API(2)-Task Control(任务控制)

本文详细介绍了FreeRTOS中任务控制的关键函数,包括vTaskDelay、vTaskDelayUntil、uxTaskPriorityGet、vTaskPrioritySet、vTaskSuspend和vTaskResume。这些函数用于实现任务的定时、优先级管理、挂起和恢复,确保实时系统的稳定运行。此外,还提到了xTaskAbortDelay函数,用于强制任务提前结束阻塞状态。
摘要由CSDN通过智能技术生成

建议由条件看FreeRTOS的官方英文参考。


目录

vTaskDelay

Example usage

函数代码

vTaskDelayUntil

xTaskDelayUntil

Example usage

函数代码

uxTaskPriorityGet

Returns

Example usage

函数代码

vTaskPrioritySet

Example usage

函数代码

vTaskSuspend

Example usage

函数代码

vTaskResume

Example usage

 函数代码

xTaskResumeFromISR

Returns

Example usage

xTaskAbortDelay

Returns

函数代码


vTaskDelay

INCLUDE_vTaskDelay 必须定义为 1 才能使该函数可用。

将任务延迟一定的ticks。 任务保持阻塞的实际时间取决于tick rate。 常数portTICK_PERIOD_MS 可用于根据滴答率(tick rate)计算实时时间 - 分辨率为一个滴答周期。

vTaskDelay()指定相对于调用vTaskDelay()的时间,任务希望解除阻止的时间。例如,指定在调用vTaskDelay() 后,100 ticks的阻塞周期将导致任务解除阻塞100 ticks。因此,vTaskDelay()并不能提供一种控制周期性任务频率的好方法,因为通过代码的路径以及其他任务和中断活动将影响调用vTaskDelay()的频率,从而影响任务下一次执行的时间。请参阅vTaskDelayUntil(),以了解另一个用于促进固定频率执行的API函数。它通过指定调用任务应该解除阻止的绝对时间(而不是相对时间)来实现这一点。

//task.h
void vTaskDelay( const TickType_t xTicksToDelay ) PRIVILEGED_FUNCTION;

xTicksToDelayThe amount of time, in tick periods, that the calling task should block.

                                        调用任务应该阻止的时间量(以周期为单位)。

Example usage

void vTaskFunction( void * pvParameters )
 {
 /* Block for 500ms. */
 const TickType_t xDelay = 500 / portTICK_PERIOD_MS;

     for( ;; )
     {
         /* Simply toggle the LED every 500ms, blocking between each toggle. */
         vToggleLED();
         vTaskDelay( xDelay );
     }
}

函数代码

//tasks.c
#if ( 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();

                /* 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();
        }
    }

#endif /* INCLUDE_vTaskDelay */

vTaskDelayUntil

INCLUDE_vTaskDelayUntil 必须定义为 1 才能使该函数可用。

将任务延迟到指定时间。 此功能可用于定期任务,以确保恒定的执行频率。

此函数在一个重要方面与vTaskDelay()不同:vTaskDelay()指定任务希望解除阻止的时间,相对于调用vTaskDelay()的时间,而vTaskDelayUntil()指定任务希望解除阻止的绝对时间。

vTaskDelay()将导致任务从调用vTaskDelay()时起按指定的刻度数阻塞。因此,很难单独使用vTaskDelay()来生成固定的执行频率,因为调用vTaskDelay()后的任务解锁与下一次调用vTaskDelay()的任务之间的时间可能不固定[任务可能在调用之间通过不同的代码路径,或者每次执行时可能会被中断或抢占不同的次数]。

vTaskDelay()指定相对于调用函数的时间的唤醒时间,而vTaskDelayUntil()指定希望解除阻止的绝对(精确)时间。

需要注意的是,如果vTaskDelayUntil()用于指定已经过去的唤醒时间,它将立即返回(无阻塞)。因此,如果周期性执行因任何原因(例如,任务暂时处于挂起状态)而停止,导致任务错过一个或多个周期性执行,则使用vTaskDelayUntil()定期执行的任务必须重新计算其所需的唤醒时间。这可以通过检查作为pxPreviousWakeTime参数的引用传递的变量与当前的勾号计数来检测。然而,在大多数使用场景下,这并不是必需的。

常数portTICK_PERIOD_MS可用于根据滴答率实时计算,分辨率为一个滴答周期。

当 RTOS 调度程序已通过调用 vTaskSuspendAll() 暂停时,不得调用此函数。

xTaskDelayUntil

INCLUDE_xTaskDelayUntil 必须定义为 1 才能使该函数可用。

任务延迟到指定的时间。此功能可用于定期任务,以确保恒定的执行频率。

此函数在一个重要方面与vTaskDelay()不同:vTaskDelay()将导致任务从调用vTaskDelay()时起阻塞指定数量的记号,而xTaskDelayUntil()将导致任务从pxPreviousWakeTime参数中指定的时间起阻塞指定数量的记号。很难单独使用vTaskDelay()来生成固定的执行频率,因为任务开始执行和调用vTaskDelay()的任务之间的时间可能不固定[任务在调用之间可能会通过不同的代码路径,或者每次执行时可能会被中断或抢占不同的次数]。xTaskDelayUntil()可用于生成恒定的执行频率。

vTaskDelay()指定相对于调用函数的时间的唤醒时间,而xTaskDelayUntil()指定希望解除阻止的绝对(精确)时间。

宏pdMS_TO_TICKS()可用于计算从指定时间(以毫秒为单位,分辨率为一个滴答周期)开始的滴答数。

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

/*
 * vTaskDelayUntil() is the older version of xTaskDelayUntil() and does not
 * return a value.
 */
#define vTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement )       
{                                                                   
    ( void ) xTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement ); 
}

pxPreviousWakeTimePointer to a variable that holds the time at which the task was last unblocked. The variable must be initialised with the current time prior to its first use (see the example below). Following this the variable is automatically updated within vTaskDelayUntil().

指向保存上次取消阻止任务的时间的变量的指针。 变量必须用当前时间初始化在首次使用之前(参见下面的示例)。 在此之后,变量是在 vTaskDelayUntil() 中自动更新。

xTimeIncrementThe cycle time period. The task will be unblocked at time (*pxPreviousWakeTime + xTimeIncrement). Calling vTaskDelayUntil with the same xTimeIncrement parameter value will cause the task to execute with a fixed interval period.

循环时间周期。 任务将在时间(*pxPreviousWakeTime+xTimeIncrement)取消阻止。使用相同的xTimeIncrement参数值调用vTaskDelayUntil将导致任务以固定的时间间隔执行。

Example usage

 // Perform an action every 10 ticks.
 void vTaskFunction( void * pvParameters )
 {
     TickType_t xLastWakeTime;
     const TickType_t xFrequency = 10;

     // Initialise the xLastWakeTime variable with the current time.
     // 用当前时间初始化 xLastWakeTime 变量。
     xLastWakeTime = xTaskGetTickCount();

     for( ;; )
     {
         // Wait for the next cycle.
         vTaskDelayUntil( &xLastWakeTime, xFrequency );

         // Perform action here.
        // 在此处执行操作
     }
 }

函数代码

//tasks.c
#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();
        {
            /* 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;
    }

#endif /* INCLUDE_xTaskDelayUntil */

uxTaskPriorityGet

INCLUDE_uxTaskPriorityGet 必须定义为 1 才能使该函数可用。 

获取任何任务的优先级。

UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;

xTask要查询的任务的句柄。 传递 NULL 句柄会导致返回调用任务的优先级。

Returns

The priority of xTask.        xTask的优先级。

Example usage

 void vAFunction( void )
 {
     TaskHandle_t xHandle;

     // Create a task, storing the handle.
     // 创建一个任务,存储句柄
     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );

     // ...

     // Use the handle to obtain the priority of the created task.
     // 使用句柄获取创建任务的优先级。
     // It was created with tskIDLE_PRIORITY, but may have changed
     // it itself.
     if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
     {
         // The task has changed its priority.
     }

     // ...

     // Is our priority higher than the created task?
     if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
     {
         // Our priority (obtained using NULL handle) is higher.
     }
 }
   

函数代码

//tasks.c
#if ( INCLUDE_uxTaskPriorityGet == 1 )

    UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )
    {
        TCB_t const * pxTCB;
        UBaseType_t uxReturn;

        taskENTER_CRITICAL();
        {
            /* If null is passed in here then it is the priority of the task
             * that called uxTaskPriorityGet() that is being queried. */
            pxTCB = prvGetTCBFromHandle( xTask );
            uxReturn = pxTCB->uxPriority;
        }
        taskEXIT_CRITICAL();

        return uxReturn;
    }

#endif /* INCLUDE_uxTaskPriorityGet */

vTaskPrioritySet

INCLUDE_vTaskPrioritySet必须定义为 1 才能使用此功能。

设置任何任务的优先级。

如果设置的优先级高于当前执行的任务,将在函数返回之前发生上下文切换。

//task.h
void vTaskPrioritySet( TaskHandle_t xTask,
                       UBaseType_t uxNewPriority ) PRIVILEGED_FUNCTION;

xTask正在设置优先级的任务的句柄。 NULL 句柄设置调用任务的优先级。

uxNewPriority将设置任务的优先级。优先级被断言小于 configMAX_PRIORITIES. 如果 configASSERT是未定义的,优先级被默默地限制在( configMAX_PRIORITIES - 1).

Example usage

 void vAFunction( void )
 {
     TaskHandle_t xHandle;
     // Create a task, storing the handle.
     // 创建一个任务,存储句柄。
     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
     // ...
     // Use the handle to raise the priority of the created task.
     // 使用句柄来提高创建任务的优先级。 
     vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 )
     // ...
     // Use a NULL handle to raise our priority to the same value.
     // 使用 NULL 句柄将我们的优先级提高到相同的值。
     vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
 }

函数代码

//tasks.h
#if ( INCLUDE_vTaskPrioritySet == 1 )

    void vTaskPrioritySet( TaskHandle_t xTask,
                           UBaseType_t uxNewPriority )
    {
        TCB_t * pxTCB;
        UBaseType_t uxCurrentBasePriority, uxPriorityUsedOnEntry;
        BaseType_t xYieldRequired = pdFALSE;

        configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) );

        /* Ensure the new priority is valid. */
        if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
        {
            uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        taskENTER_CRITICAL();
        {
            /* If null is passed in here then it is the priority of the calling
             * task that is being changed. */
            pxTCB = prvGetTCBFromHandle( xTask );

            traceTASK_PRIORITY_SET( pxTCB, uxNewPriority );

            #if ( configUSE_MUTEXES == 1 )
                {
                    uxCurrentBasePriority = pxTCB->uxBasePriority;
                }
            #else
                {
                    uxCurrentBasePriority = pxTCB->uxPriority;
                }
            #endif

            if( uxCurrentBasePriority != uxNewPriority )
            {
                /* The priority change may have readied a task of higher
                 * priority than the calling task. */
                if( uxNewPriority > uxCurrentBasePriority )
                {
                    if( pxTCB != pxCurrentTCB )
                    {
                        /* The priority of a task other than the currently
                         * running task is being raised.  Is the priority being
                         * raised above that of the running task? */
                        if( uxNewPriority >= pxCurrentTCB->uxPriority )
                        {
                            xYieldRequired = pdTRUE;
                        }
                        else
                        {
                            mtCOVERAGE_TEST_MARKER();
                        }
                    }
                    else
                    {
                        /* The priority of the running task is being raised,
                         * but the running task must already be the highest
                         * priority task able to run so no yield is required. */
                    }
                }
                else if( pxTCB == pxCurrentTCB )
                {
                    /* Setting the priority of the running task down means
                     * there may now be another task of higher priority that
                     * is ready to execute. */
                    xYieldRequired = pdTRUE;
                }
                else
                {
                    /* Setting the priority of any other task down does not
                     * require a yield as the running task must be above the
                     * new priority of the task being modified. */
                }

                /* Remember the ready list the task might be referenced from
                 * before its uxPriority member is changed so the
                 * taskRESET_READY_PRIORITY() macro can function correctly. */
                uxPriorityUsedOnEntry = pxTCB->uxPriority;

                #if ( configUSE_MUTEXES == 1 )
                    {
                        /* Only change the priority being used if the task is not
                         * currently using an inherited priority. */
                        if( pxTCB->uxBasePriority == pxTCB->uxPriority )
                        {
                            pxTCB->uxPriority = uxNewPriority;
                        }
                        else
                        {
                            mtCOVERAGE_TEST_MARKER();
                        }

                        /* The base priority gets set whatever. */
                        pxTCB->uxBasePriority = uxNewPriority;
                    }
                #else /* if ( configUSE_MUTEXES == 1 ) */
                    {
                        pxTCB->uxPriority = uxNewPriority;
                    }
                #endif /* if ( configUSE_MUTEXES == 1 ) */

                /* Only reset the event list item value if the value is not
                 * being used for anything else. */
                if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
                {
                    listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                /* If the task is in the blocked or suspended list we need do
                 * nothing more than change its priority variable. However, if
                 * the task is in a ready list it needs to be removed and placed
                 * in the list appropriate to its new priority. */
                if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
                {
                    /* The task is currently in its ready list - remove before
                     * adding it to it's new ready list.  As we are in a critical
                     * section we can do this even if the scheduler is suspended. */
                    if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
                    {
                        /* It is known that the task is in its ready list so
                         * there is no need to check again and the port level
                         * reset macro can be called directly. */
                        portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority );
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

                    prvAddTaskToReadyList( pxTCB );
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                if( xYieldRequired != pdFALSE )
                {
                    taskYIELD_IF_USING_PREEMPTION();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                /* Remove compiler warning about unused variables when the port
                 * optimised task selection is not being used. */
                ( void ) uxPriorityUsedOnEntry;
            }
        }
        taskEXIT_CRITICAL();
    }

#endif /* INCLUDE_vTaskPrioritySet */

vTaskSuspend

INCLUDE_vTaskSuspend 必须定义为 1 才能使该函数可用。

暂停任何任务。 暂停任务时,无论其优先级如何,都不会获得任何微控制器处理时间。

对 vTaskSuspend 的调用不是累积的——即在同一个任务上调用 vTaskSuspend () 两次仍然只需要调用一次 vTaskResume () 来准备挂起的任务。

//task.h
void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION;

xTaskToSuspend处理被挂起的任务。 传递 NULL 句柄将导致调用任务被挂起。

Example usage

 void vAFunction( void )
 {
     TaskHandle_t xHandle;

     // Create a task, storing the handle.
     // 创建一个任务,存储句柄。
     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );

     // ...

     // Use the handle to suspend the created task.
     // 使用句柄挂起创建的任务。
     vTaskSuspend( xHandle );

     // ...

     // The created task will not run during this period, unless
     // 创建的任务在此期间不会运行,除非
     // another task calls vTaskResume( xHandle ).
     // 另一个任务调用 vTaskResume(xHandle)。 

     //...

     // Suspend ourselves.
     // 暂停我们自己。
     vTaskSuspend( NULL );

     // We cannot get here unless another task calls vTaskResume
     // 我们无法到达这里,除非另一个任务调用 vTaskResume
     // with our handle as the parameter.
     // 以我们的句柄为参数。
 }
   

函数代码

//tasks.c
#if ( INCLUDE_vTaskSuspend == 1 )

    void vTaskSuspend( TaskHandle_t xTaskToSuspend )
    {
        TCB_t * pxTCB;

        taskENTER_CRITICAL();
        {
            /* If null is passed in here then it is the running task that is
             * being suspended. */
            pxTCB = prvGetTCBFromHandle( xTaskToSuspend );

            traceTASK_SUSPEND( pxTCB );

            /* Remove task from the ready/delayed list and place in the
             * suspended list. */
            if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
            {
                taskRESET_READY_PRIORITY( pxTCB->uxPriority );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            /* Is the task waiting on an event also? */
            if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
            {
                ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );

            #if ( configUSE_TASK_NOTIFICATIONS == 1 )
                {
                    BaseType_t x;

                    for( x = 0; x < configTASK_NOTIFICATION_ARRAY_ENTRIES; x++ )
                    {
                        if( pxTCB->ucNotifyState[ x ] == taskWAITING_NOTIFICATION )
                        {
                            /* The task was blocked to wait for a notification, but is
                             * now suspended, so no notification was received. */
                            pxTCB->ucNotifyState[ x ] = taskNOT_WAITING_NOTIFICATION;
                        }
                    }
                }
            #endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
        }
        taskEXIT_CRITICAL();

        if( xSchedulerRunning != pdFALSE )
        {
            /* Reset the next expected unblock time in case it referred to the
             * task that is now in the Suspended state. */
            taskENTER_CRITICAL();
            {
                prvResetNextTaskUnblockTime();
            }
            taskEXIT_CRITICAL();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        if( pxTCB == pxCurrentTCB )
        {
            if( xSchedulerRunning != pdFALSE )
            {
                /* The current task has just been suspended. */
                configASSERT( uxSchedulerSuspended == 0 );
                portYIELD_WITHIN_API();
            }
            else
            {
                /* The scheduler is not running, but the task that was pointed
                 * to by pxCurrentTCB has just been suspended and pxCurrentTCB
                 * must be adjusted to point to a different task. */
                if( listCURRENT_LIST_LENGTH( &xSuspendedTaskList ) == uxCurrentNumberOfTasks ) /*lint !e931 Right has no side effect, just volatile. */
                {
                    /* No other tasks are ready, so set pxCurrentTCB back to
                     * NULL so when the next task is created pxCurrentTCB will
                     * be set to point to it no matter what its relative priority
                     * is. */
                    pxCurrentTCB = NULL;
                }
                else
                {
                    vTaskSwitchContext();
                }
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

#endif /* INCLUDE_vTaskSuspend */

vTaskResume

INCLUDE_vTaskSuspend 必须定义为 1 才能使该函数可用。

恢复暂停的任务。

通过一次或多次调用 vTaskSuspend () 暂停的任务将通过一次调用 vTaskResume () 再次可供运行。

//task.h
void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;

xTaskToResumeHandle to the task being readied. 处理要准备的任务。

Example usage

 void vAFunction( void )
 {
 TaskHandle_t xHandle;

     // Create a task, storing the handle.
     // 创建一个任务,存储句柄。
     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );

     // ...

     // Use the handle to suspend the created task.
     // 使用句柄挂起创建的任务。
     vTaskSuspend( xHandle );

     // ...

     // The created task will not run during this period, unless
     // 创建的任务在此期间不会运行,除非
     // another task calls vTaskResume( xHandle ).
     // 另一个任务调用 vTaskResume(xHandle)。 

     //...

     // Resume the suspended task ourselves.
     // 我们自己恢复挂起的任务。
     vTaskResume( xHandle );

     // The created task will once again get microcontroller processing
     // 创建的任务将再次得到微控制器处理
     // time in accordance with its priority within the system.
     //时间按照其在系统内的优先级。
 }
   

 函数代码

//tasks.c
#if ( INCLUDE_vTaskSuspend == 1 )

    void vTaskResume( TaskHandle_t xTaskToResume )
    {
        TCB_t * const pxTCB = xTaskToResume;

        /* It does not make sense to resume the calling task. */
        configASSERT( xTaskToResume );

        /* The parameter cannot be NULL as it is impossible to resume the
         * currently executing task. */
        if( ( pxTCB != pxCurrentTCB ) && ( pxTCB != NULL ) )
        {
            taskENTER_CRITICAL();
            {
                if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
                {
                    traceTASK_RESUME( pxTCB );

                    /* The ready list can be accessed even if the scheduler is
                     * suspended because this is inside a critical section. */
                    ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
                    prvAddTaskToReadyList( pxTCB );

                    /* A higher priority task may have just been resumed. */
                    if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
                    {
                        /* This yield may not cause the task just resumed to run,
                         * but will leave the lists in the correct state for the
                         * next yield. */
                        taskYIELD_IF_USING_PREEMPTION();
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            taskEXIT_CRITICAL();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }

#endif /* INCLUDE_vTaskSuspend */

xTaskResumeFromISR

INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1 才能使该函数可用。

恢复可以从 ISR 中调用的挂起任务的函数。

通过对 vTaskSuspend() 的多次调用而暂停的任务将通过对 xTaskResumeFromISR() 的一次调用再次可供运行。

xTaskResumeFromISR()通常被认为是一个危险的函数,因为它的操作没有被锁定。因此,如果中断可能在任务暂停之前到达,因此中断丢失,则绝对不应使用它来同步任务与中断。使用信号量,或者最好是直接发送到任务的通知,可以避免这种情况。

//task.h
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;

xTaskToResumeHandle to the task being readied.        处理要准备的任务。

Returns

pdTRUE if resuming the task should result in a context switch, otherwise pdFALSE. This is used by the ISR to determine if a context switch may be required following the ISR.

如果恢复任务会导致上下文切换,则为 pdTRUE,否则为 pdFALSE。 ISR 使用它来确定是否需要在 ISR 之后进行上下文切换。

Example usage

 TaskHandle_t xHandle;

 void vAFunction( void )
 {
     // Create a task, storing the handle.
     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );

     // ... Rest of code.
 }

 void vTaskCode( void *pvParameters )
 {
     // The task being suspended and resumed.
     for( ;; )
     {
         // ... Perform some function here.

         // The task suspends itself.
         // 任务自行挂起。
         vTaskSuspend( NULL );

         // The task is now suspended, so will not reach here until the ISR resumes it.
     }
 }


 void vAnExampleISR( void )
 {
     BaseType_t xYieldRequired;

     // Resume the suspended task.
     // 恢复挂起的任务。
     xYieldRequired = xTaskResumeFromISR( xHandle );

     // We should switch context so the ISR returns to a different task.
     // NOTE:  How this is done depends on the port you are using.  Check
     // the documentation and examples for your port.
     // 我们应该切换上下文,以便 ISR 返回到不同的任务。
     // 注意:如何完成取决于您使用的端口。  查看
     // 您的端口的文档和示例。
     portYIELD_FROM_ISR( xYieldRequired );
 }

xTaskAbortDelay

INCLUDE_xTaskAbortDelay 必须是 定义为 1 以使此功能可用。

Forces a task to leave the Blocked state, and enter the Ready state, even if the event the task was in the Blocked state to wait for has not occurred, and any specified timeout has not expired.

强制任务离开阻止状态,并进入就绪状态,即使任务处于阻止状态等待的事件尚未发生,且任何指定的超时尚未过期。

//task.h
BaseType_t xTaskAbortDelay( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;

xTask

The handle of the task that will be forced out of the Blocked state.

To obtain a task's handle create the task using xTaskCreate() and make use of the pxCreatedTask parameter, or create the task using xTaskCreateStatic() and store the returned value, or use the task's name in a call to xTaskGetHandle().

将被强制退出阻止状态的任务的句柄。

要获取任务的句柄,请使用xTaskCreate()创建任务并使用pxCreatedTask参数,或使用xTaskCreateStatic()创建任务并存储返回值,或在调用xTaskGetHandle()时使用任务的名称。

Returns

If the task referenced by xTask was not in the Blocked state then pdFAIL is returned. Otherwise pdPASS is returned.

如果xTask引用的任务未处于阻止状态,则返回pdFAIL。否则将返回pdPASS。

函数代码

//tasks.c
#if ( INCLUDE_xTaskAbortDelay == 1 )

    BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
    {
        TCB_t * pxTCB = xTask;
        BaseType_t xReturn;

        configASSERT( pxTCB );

        vTaskSuspendAll();
        {
            /* A task can only be prematurely removed from the Blocked state if
             * it is actually in the Blocked state. */
            if( eTaskGetState( xTask ) == eBlocked )
            {
                xReturn = pdPASS;

                /* Remove the reference to the task from the blocked list.  An
                 * interrupt won't touch the xStateListItem because the
                 * scheduler is suspended. */
                ( void ) uxListRemove( &( pxTCB->xStateListItem ) );

                /* Is the task waiting on an event also?  If so remove it from
                 * the event list too.  Interrupts can touch the event list item,
                 * even though the scheduler is suspended, so a critical section
                 * is used. */
                taskENTER_CRITICAL();
                {
                    if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
                    {
                        ( void ) uxListRemove( &( pxTCB->xEventListItem ) );

                        /* This lets the task know it was forcibly removed from the
                         * blocked state so it should not re-evaluate its block time and
                         * then block again. */
                        pxTCB->ucDelayAborted = pdTRUE;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                taskEXIT_CRITICAL();

                /* Place the unblocked task into the appropriate ready list. */
                prvAddTaskToReadyList( pxTCB );

                /* A task being unblocked cannot cause an immediate context
                 * switch if preemption is turned off. */
                #if ( configUSE_PREEMPTION == 1 )
                    {
                        /* Preemption is on, but a context switch should only be
                         *  performed if the unblocked task has a priority that is
                         *  equal to or higher than the currently executing task. */
                        if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
                        {
                            /* Pend the yield to be performed when the scheduler
                             * is unsuspended. */
                            xYieldPending = pdTRUE;
                        }
                        else
                        {
                            mtCOVERAGE_TEST_MARKER();
                        }
                    }
                #endif /* configUSE_PREEMPTION */
            }
            else
            {
                xReturn = pdFAIL;
            }
        }
        ( void ) xTaskResumeAll();

        return xReturn;
    }

#endif /* INCLUDE_xTaskAbortDelay */

OK,每日一学习达成~ ~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值