自学内容网 自学内容网

FreeRTOS保姆级教程(以STM32为例)—任务创建和任务控制API说明

目录

一、任务创建:

(1)TaskHandle_t  任务句柄

(2) xTaskCreate:

函数原型:

参数说明:

返回值:

示例: 

注意事项:

用法示例:

(3)xTaskCreateStatic :

函数原型:

参数说明:

返回值:

使用场景:

注意事项:

用法示例:

 (4)vTaskDelete:

函数原型:

参数:

功能:

注意事项:

配置:

用法示例:

二、任务控制: 

(1)vTaskDelay:

函数原型:

参数:

功能:

注意事项:

配置:

用法示例:

计算实际延迟时间:

替代函数:

(2)vTaskDelayUntil:

函数原型:

参数:

功能:

注意事项:

配置:

用法示例:

计算实际延迟时间:

 (3)uxTaskPriorityGet :

函数原型:

参数:

返回值:

功能:

注意事项:

用法示例:

优先级比较:

 (4)vTaskPrioritySet :

函数原型:

参数:

功能:

注意事项:

用法示例:

优先级设置:

(5)vTaskSuspend:

函数原型:

参数:

功能:

注意事项:

用法示例:

挂起和恢复任务:

 (6)vTaskResume:

函数原型:

参数:

功能:

注意事项:

用法示例:

挂起和恢复任务:

(7)xTaskResumeFromISR:

函数原型:

参数:

返回值:

功能:

注意事项:

用法示例:

上下文切换:

 (8)xTaskAbortDelay :

函数原型:

参数:

返回值:

功能:

注意事项:

用法示例:

 (9)uxTaskPriorityGetFromISR:

函数原型:

参数:

返回值:

功能:

注意事项:

用法示例:

(10)uxTaskBasePriorityGet:

函数原型:

参数:

返回值:

功能:

注意事项:

用法示例:

(11)uxTaskBasePriorityGetFromISR:

函数原型:

参数:

返回值:

功能:

注意事项:

用法示例:


一、任务创建:

(1)TaskHandle_t  任务句柄

  • TaskHandle_t 是 FreeRTOS 中用于标识任务句柄的数据类型,它通常指向任务控制块(TCB)。当你创建一个任务时,例如使用 xTaskCreate 函数,你可以提供一个指针参数来接收新创建的任务的句柄。这个句柄可以用来对任务进行操作,比如删除任务。
TaskHandle_t myTaskHandler; // 定义一个任务句柄变量,用于跟踪任务。

(2) xTaskCreate:

  • 创建一项新任务并将其添加到准备运行的任务列表中。
  • configSUPPORT_DYNAMIC_ALLOCATION 必须在 FreeRTOSConfig.h 中设置为 1,或处于未定义状态(默认为 1), 才可使用此 RTOS API 函数。
  • 每项任务都需要 RAM 来保存任务状态,并由任务用作其堆栈。
  • 如果 使用 xTaskCreate() 创建任务,则所需的 RAM 会自动 从 FreeRTOS 堆分配。
  • 如果使用 xTaskCreateStatic() 创建任务, 则 RAM 由应用程序编写者提供,因此可以在编译时静态分配。
  • 如果使用的是 FreeRTOS-MPU,建议 使用 xTaskCreateRestricted(),而不是 xTaskCreate()。

函数原型:

BaseType_t xTaskCreate(
    TaskFunction_t pvTaskCode,
    const char * const pcName,
    const configSTACK_DEPTH_TYPE uxStackDepth,
    void *pvParameters,
    UBaseType_t uxPriority,
    TaskHandle_t *pxCreatedTask
);

参数说明:

  • pvTaskCode:指向任务函数的指针,任务函数是实现任务逻辑的函数。
  • pcName:任务的名称,主要用于调试目的,也可以用于通过名称获取任务的句柄。
  • uxStackDepth:任务堆栈的深度,以字数(word)为单位,不是字节。具体的堆栈大小取决于处理器的架构(如16位、32位等)。
  • pvParameters:传递给任务的参数,如果是一个变量的地址,那么在任务执行期间该变量必须有效。
  • uxPriority:任务的优先级,可以结合 portPRIVILEGE_BIT 来创建特权任务。
  • pxCreatedTask:可选参数,用于存储创建的任务的句柄,可以用于后续的任务操作,如删除任务。

返回值:

  • pdPASS:表示任务成功创建。
  • errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:表示创建任务失败,通常是因为内存不足。

示例: 

// 创建名为"led1"的任务,栈大小为64字节,优先级为2,任务函数为myTask1,不传递参数给任务。
    xTaskCreate(myTask1, "led1", 64, NULL, 2, &myTaskHandler);

注意事项:

  • 确保 configSUPPORT_DYNAMIC_ALLOCATION 在 FreeRTOSConfig.h 中被定义为 1,以启用动态内存分配。
  • 如果使用 MPU(内存保护单元),建议使用 xTaskCreateRestricted 而不是 xTaskCreate
  • 任务函数应该永远不返回,如果需要结束任务,应该在任务内部调用 vTaskDelete
  • 传递给 pvParameters 的参数在任务整个生命周期内都必须有效,如果需要在任务结束后释放资源,应在任务函数内部处理。

用法示例:

//要创建的任务。
void vTaskCode( void * pvParameters )
{
   //参数值预期为1,因为1是在下面的xTaskCreate()调用中的pvParameters值。
    configASSERT( ( ( uint32_t ) pvParameters ) == 1 );

    for( ;; )//无限循环
    {
        //任务代码在这里。
    }
}

//创建任务的函数
void vOtherFunction( void )
{
    BaseType_t xReturned;
    TaskHandle_t xHandle = NULL;

    //创建任务,存储句柄。
    xReturned = xTaskCreate(
                    vTaskCode,       //执行任务的函数。
                    "NAME",          //任务的文本名称。
                    STACK_SIZE,      //以字为单位的堆栈大小,而不是字节。
                    ( void * ) 1,    //传入任务的参数。
                    tskIDLE_PRIORITY,//创建任务的优先级。
                    &xHandle );      //用于传递创建的任务句柄。

    if( xReturned == pdPASS )
    {
       //任务创建成功。使用任务句柄删除任务。
        vTaskDelete( xHandle );
    }
}

(3)xTaskCreateStatic

xTaskCreateStatic 是 FreeRTOS 提供的一个 API 函数,它允许开发者在创建任务时使用静态内存分配,即在编译时就已经分配好内存。这种方式与 xTaskCreate 动态分配内存的方式相对。

函数原型:

TaskHandle_t xTaskCreateStatic(
    TaskFunction_t pxTaskCode,
    const char * const pcName,
    const uint32_t ulStackDepth,
    void * const pvParameters,
    UBaseType_t uxPriority,
    StackType_t * const puxStackBuffer,
    StaticTask_t * const pxTaskBuffer
);

参数说明:

  • pxTaskCode:指向任务函数的指针,这是任务的入口点,任务函数不能返回,通常包含无限循环。
  • pcName:任务的名称,主要用于调试目的,也可以通过名称获取任务句柄。
  • ulStackDepth:任务堆栈的深度,以 StackType_t 类型的数组索引为单位。这个值表示堆栈数组的大小。
  • pvParameters:传递给任务的参数,这个参数在任务函数中可用。
  • uxPriority:任务的优先级,如果系统支持 MPU,可以通过设置 portPRIVILEGE_BIT 来创建特权任务。
  • puxStackBuffer:指向一个 StackType_t 类型的数组,这个数组用作任务的堆栈,必须在函数外部声明,以确保其内存在任务生命周期内持久存在。
  • pxTaskBuffer:指向一个 StaticTask_t 类型的变量,这个变量用于保存任务的控制块(TCB),同样必须在函数外部声明。

返回值:

  • 如果 puxStackBuffer 和 pxTaskBuffer 都不为 NULL,则函数会创建任务,并返回任务的句柄。
  • 如果 puxStackBuffer 或 pxTaskBuffer 为 NULL,则函数不会创建任务,并返回 NULL。

使用场景:

xTaskCreateStatic 适用于以下情况:

  • 当系统的内存资源非常有限,需要在编译时就确定任务使用的内存。
  • 当需要避免动态内存分配可能带来的内存碎片问题。
  • 当需要确保任务的内存使用可预测和确定。

注意事项:

  • 必须确保 puxStackBuffer 和 pxTaskBuffer 指向的内存区域在任务生命周期内不会被改变或释放。
  • configSUPPORT_STATIC_ALLOCATION 必须在 FreeRTOSConfig.h 中定义为 1,才能使用 xTaskCreateStatic
  • 如果你的系统使用 MPU,建议使用 xTaskCreateRestricted 来代替 xTaskCreateStatic,以便设置任务的内存访问权限。

使用 xTaskCreateStatic 可以提供更细粒度的内存管理控制,但同时也要求开发者更加注意内存的使用和管理。

用法示例:

//正在创建的任务将用作其堆栈的缓冲区的大小。
//注意:这是堆栈将保存的单词数,而不是单词数字节。
//例如,如果每个堆栈项都是32位,并且这个设置为100,
//然后将分配400字节(100 * 32位)。    
    #define STACK_SIZE 200

   //保存正在创建任务的TCB的结构。
    StaticTask_t xTaskBuffer;

   //正在创建的任务将用作栈的缓冲区。
   //注意这是StackType_t变量的数组。
   //StackType_t的大小取决于RTOS端口。
    StackType_t xStack[ STACK_SIZE ];


   //执行创建任务的函数。
    void vTaskCode( void * pvParameters )
    {
       //参数值预期为1,因为1是在在调用xTaskCreateStatic()中的pvParameters值。
        configASSERT( ( uint32_t ) pvParameters == 1UL );

        for( ;; )
        {
           //任务代码在这里。
        }
    }

    //创建任务的函数。
    void vOtherFunction( void )
    {
        TaskHandle_t xHandle = NULL;

        //创建不使用任何动态内存分配的任务。
        xHandle = xTaskCreateStatic(
                      vTaskCode,       //执行任务的函数。
                      "NAME",          //任务的文本名称。
                      STACK_SIZE,      //xStack数组的索引数。
                      ( void * ) 1,    //传入任务的参数。
                      tskIDLE_PRIORITY,//创建任务的优先级。
                      xStack,          //作为任务栈的数组。
                      &xTaskBuffer );  //保存任务数据结构的变量

        //puxStackBuffer和pxTaskBuffer不是NULL,
        //所以任务将有并且xHandle将是任务的句柄。
        //使用手柄暂停任务。
        [vTaskSuspend](/Documentation/02-Kernel/04-API-references/02-Task-control/06-vTaskSuspend)( xHandle );
    }

 (4)vTaskDelete:

vTaskDelete 是 FreeRTOS 提供的一个函数,用于删除一个任务。当一个任务不再需要时,可以使用这个函数来释放与该任务相关的资源。

函数原型:

void vTaskDelete( TaskHandle_t xTask );

参数:

  • xTask:要删除的任务的句柄。如果传递 NULL,则会删除调用 vTaskDelete 函数的任务本身。

功能:

  • vTaskDelete 会从 RTOS 内核管理中移除指定的任务,包括所有就绪、阻塞、挂起和事件列表。
  • 被删除的任务的堆栈和任务控制块(TCB)将由空闲任务在适当的时候释放,因此不需要手动释放这些资源。
  • 任务代码中动态分配的内存或其他资源不会自动释放,应在任务删除之前手动释放。

注意事项:

  • 确保在删除任务之前,该任务已经完成了所有必要的清理工作,包括释放它可能持有的任何资源。
  • 如果传递 NULL 给 vTaskDelete,那么当前执行的任务(即调用 vTaskDelete 的任务)将被删除。
  • 在任务删除后,不应再使用与该任务相关联的任何句柄或资源。
  • 确保空闲任务获得足够的处理时间,以便它能够释放被删除任务的资源。

配置:

  • 为了使用 vTaskDelete 函数,FreeRTOSConfig.h 文件中的 INCLUDE_vTaskDelete 宏必须定义为 1。如果这个宏没有定义,vTaskDelete 函数将不会被包含在编译中。

用法示例:

void vTaskFunction(void *pvParameters)
{
    for (;;)
    {
        // 任务代码
    }
}

void vOtherFunction(void)
{
    TaskHandle_t xHandle = NULL;

    // 创建任务,存储句柄
    xTaskCreate(vTaskFunction, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle);

    // 做一些工作...

    // 使用句柄删除任务
    if (xHandle != NULL)
    {
        vTaskDelete(xHandle);
    }
}

在这个例子中,vTaskFunction 是一个简单的任务函数,它将无限循环执行。vOtherFunction 创建了这个任务,并保留了任务的句柄。在执行了一些工作之后,它使用 vTaskDelete 来删除这个任务。

二、任务控制: 

(1)vTaskDelay:

vTaskDelay 是 FreeRTOS 提供的一个函数,用于实现任务的延迟(阻塞)。这个函数使调用它的任务暂停执行指定的滴答数(ticks),从而让出 CPU 给其他任务。

函数原型:

void vTaskDelay( const TickType_t xTicksToDelay );

参数:

  • xTicksToDelay:任务将要延迟的滴答数(ticks)。这个值表示任务想要延迟的时间,以系统的滴答频率为单位。

功能:

  • vTaskDelay 按照指定的滴答数延迟调用它的任务。
  • 延迟时间的实际长度取决于系统的滴答频率,这通常在 FreeRTOSConfig.h 文件中定义。

注意事项:

  • vTaskDelay 延迟的是任务的执行,而不是实际的时间。这意味着如果系统非常繁忙,任务可能会延迟更长时间。
  • vTaskDelay 不应该用于生成精确的定时事件,因为它受到任务调度和系统负载的影响。

配置:

  • 为了使用 vTaskDelay 函数,FreeRTOSConfig.h 文件中的 INCLUDE_vTaskDelay 宏必须定义为 1。如果这个宏没有定义,vTaskDelay 函数将不会被包含在编译中。

用法示例:

以下是一个使用 vTaskDelay 的示例,其中任务每 500 毫秒切换一次 LED 的状态:

void vToggleLED(void) {
    // 切换 LED 的代码
}

void vTaskFunction(void *pvParameters) {
    /* 计算 500ms 对应的滴答数 */
    const TickType_t xDelay = 500 / portTICK_PERIOD_MS;

    for (;;) {
        /* 每 500ms 切换 LED 状态,然后延迟 */
        vToggleLED();
        vTaskDelay(xDelay);
    }
}

在这个例子中,vToggleLED 是一个假设的函数,用于切换 LED 的状态。vTaskFunction 是一个任务函数,它使用 vTaskDelay 来实现每 500 毫秒切换一次 LED。

计算实际延迟时间:

portTICK_PERIOD_MS 是一个常量,定义了每个滴答周期的时长(以毫秒为单位)。要计算延迟时间,可以使用以下公式:

const TickType_t xDelay = desiredTimeInMs / portTICK_PERIOD_MS;

其中 desiredTimeInMs 是希望延迟的时间(以毫秒为单位)。

替代函数:

  • vTaskDelayUntil:如果您需要以固定频率执行任务,可以使用 vTaskDelayUntil 函数。它允许您指定任务下次应该被唤醒的绝对时间,而不是相对时间。

(2)vTaskDelayUntil:

vTaskDelayUntil 是 FreeRTOS 提供的一个函数,它允许任务以固定的频率执行,而不是简单地延迟一定的时间。这个函数特别适合于需要周期性执行的任务。

函数原型:

void vTaskDelayUntil( TickType_t *pxPreviousWakeTime,
 const TickType_t xTimeIncrement );

参数:

  • pxPreviousWakeTime:指向一个变量的指针,该变量用于保存任务最后一次解除阻塞的时间。在首次使用前,这个变量必须用当前时间(xTaskGetTickCount)初始化。在这之后,vTaskDelayUntil 会在每次调用时自动更新这个变量。
  • xTimeIncrement:周期时间段,以滴答数为单位。任务将在 (*pxPreviousWakeTime + xTimeIncrement) 的时间解除阻塞。使用相同的 xTimeIncrement 参数值调用 vTaskDelayUntil 将导致任务以固定的间隔执行。

功能:

  • vTaskDelayUntil 确保任务以恒定的执行频率运行。
  • 与 vTaskDelay 不同,vTaskDelayUntil 指定任务希望解除阻塞的绝对时间,而不是相对于调用时间的延迟。

注意事项:

  • 如果 vTaskDelayUntil 被用于指定已经过去的唤醒时间,该函数将立即返回(不阻塞)。
  • 使用 vTaskDelayUntil 定期执行的任务,在周期性执行因任何原因停止(例如,任务被挂起)而导致任务错过一个或多个周期性执行时,必须重新计算其所需的唤醒时间。
  • 当调用了 vTaskSuspendAll 挂起 RTOS 调度器时,不得调用此函数。

配置:

  • 为了使用 vTaskDelayUntil 函数,FreeRTOSConfig.h 文件中的 INCLUDE_vTaskDelayUntil 宏必须定义为 1。如果这个宏没有定义,vTaskDelayUntil 函数将不会被包含在编译中。

用法示例:

以下是一个使用 vTaskDelayUntil 的示例,其中任务每 10 个滴答周期执行一次动作:

void vTaskFunction(void *pvParameters)
{
    TickType_t xLastWakeTime;
    const TickType_t xFrequency = 10;

    // 初始化 xLastWakeTime 变量为当前时间
    xLastWakeTime = xTaskGetTickCount();

    for (;;)
    {
        // 等待下一个周期
        vTaskDelayUntil(&xLastWakeTime, xFrequency);

        // 在这里执行动作
    }
}

在这个例子中,xLastWakeTime 被初始化为当前的滴答计数,然后任务会无限循环,每次循环都会调用 vTaskDelayUntil 来延迟到下一个周期。xFrequency 定义了任务执行的频率。

计算实际延迟时间:

portTICK_PERIOD_MS 是一个常量,定义了每个滴答周期的时长(以毫秒为单位)。要计算延迟时间,可以使用以下公式:

const TickType_t xTimeIncrement = desiredTimeInMs / portTICK_PERIOD_MS;

其中 desiredTimeInMs 是希望任务执行的周期(以毫秒为单位)。

 (3)uxTaskPriorityGet

uxTaskPriorityGet 是 FreeRTOS 提供的一个函数,用于获取指定任务的优先级。这个函数可以查询任何任务的优先级,包括调用它的任务。

函数原型:

UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask );

参数:

  • xTask:待查询任务的句柄。如果传递 NULL,则函数返回调用任务的优先级。

返回值:

  • 返回指定任务的优先级。

功能:

  • uxTaskPriorityGet 用于获取任务的当前优先级。
  • 如果任务的优先级在运行时被改变,可以使用这个函数来获取最新的优先级。

注意事项:

  • 在使用 uxTaskPriorityGet 之前,确保在 FreeRTOSConfig.h 中定义了 INCLUDE_uxTaskPriorityGet 为 1,以确保函数被包含在编译中。

用法示例:

以下是一个使用 uxTaskPriorityGet 的示例:

void vTaskFunction(void *pvParameters)
{
    // ... Task code ...
}

void vAFunction(void)
{
    TaskHandle_t xHandle;

    // 创建一个任务,并存储句柄
    xTaskCreate(vTaskFunction, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle);

    // ...

    // 使用句柄获取创建的任务的优先级
    // 它被创建时使用的是 tskIDLE_PRIORITY,但可能已经改变了
    if(uxTaskPriorityGet(xHandle) != tskIDLE_PRIORITY)
    {
        // 任务已经改变了它的优先级
    }

    // ...

    // 我们的任务优先级是否高于创建的任务?
    if(uxTaskPriorityGet(xHandle) < uxTaskPriorityGet(NULL))
    {
        // 我们的任务优先级(使用 NULL 句柄获得)更高
    }
}

在这个例子中,vAFunction 函数创建了一个任务,并获取了它的句柄 xHandle。然后,它使用 uxTaskPriorityGet 来检查任务的优先级是否发生了变化。如果传递 NULLuxTaskPriorityGet,它将返回调用任务(即 vAFunction 函数中的当前任务)的优先级。

优先级比较:

  • 优先级数值越低,优先级越高。因此,如果一个任务的优先级数值小于另一个任务的优先级数值,那么它具有更高的优先级。

 (4)vTaskPrioritySet

vTaskPrioritySet 是 FreeRTOS 提供的一个函数,用于动态设置任务的优先级。这个函数允许你在运行时更改任务的优先级,从而可以对任务的执行顺序进行调整。

函数原型:

void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );

参数:

  • xTask:要设置优先级的任务的句柄。如果传递 NULL,则设置调用此函数的任务的优先级。
  • uxNewPriority:要设置的新优先级。这个值必须小于 configMAX_PRIORITIES,这是在 FreeRTOSConfig.h 中定义的系统支持的最大优先级数。

功能:

  • vTaskPrioritySet 用于更改任务的优先级。
  • 如果正在设置的优先级高于当前执行任务的优先级,并且当前任务不是唯一的最高优先级任务,则在函数返回之前会发生上下文切换。

注意事项:

  • 在使用 vTaskPrioritySet 之前,确保在 FreeRTOSConfig.h 中定义了 INCLUDE_vTaskPrioritySet 为 1,以确保函数被包含在编译中。
  • 改变任务优先级可能会影响系统的实时性,因此需要谨慎使用。
  • 如果任务的优先级被提高,它可能会立即抢占其他任务的执行(如果它是当前可运行的最高优先级任务)。
  • 如果任务的优先级被降低,它可能会立即被其他更高优先级的任务抢占。

用法示例:

以下是一个使用 vTaskPrioritySet 的示例:

void vTaskFunction(void *pvParameters)
{
    for (;;)
    {
        // 任务代码
    }
}

void vAFunction(void)
{
    TaskHandle_t xHandle;

    // 创建一个任务,并存储句柄
    xTaskCreate(vTaskFunction, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle);

    // ...

    // 使用句柄提高创建的任务的优先级
    vTaskPrioritySet(xHandle, tskIDLE_PRIORITY + 1);

    // ...

    // 使用 NULL 句柄提高我们自己的优先级到相同的值
    vTaskPrioritySet(NULL, tskIDLE_PRIORITY + 1);
}

在这个例子中,vAFunction 函数创建了一个任务,并获取了它的句柄 xHandle。然后,它使用 vTaskPrioritySet 来提高任务的优先级。如果传递 NULLvTaskPrioritySet,它将提高调用任务(即 vAFunction 函数中的当前任务)的优先级。

优先级设置:

  • 优先级数值越低,优先级越高。因此,tskIDLE_PRIORITY + 1 表示将任务的优先级提高到比空闲任务更高的级别。

(5)vTaskSuspend:

vTaskSuspend 是 FreeRTOS 提供的一个函数,用于挂起(暂停)一个任务。挂起的任务将无法运行,直到它被另一个任务恢复。

函数原型:

void vTaskSuspend( TaskHandle_t xTaskToSuspend );

参数:

  • xTaskToSuspend:要挂起的任务的句柄。如果传递 NULL,则挂起调用此函数的任务本身。

功能:

  • vTaskSuspend 用于挂起指定的任务。
  • 挂起的任务将从就绪状态列表中移除,并且不会获得任何 CPU 时间,直到它被恢复。
  • 对 vTaskSuspend 的调用不会累积。这意味着即使一个任务被多次挂起,也只需要一次对应的 vTaskResume 调用来恢复它。

注意事项:

  • 在使用 vTaskSuspend 之前,确保在 FreeRTOSConfig.h 中定义了 INCLUDE_vTaskSuspend 为 1,以确保函数被包含在编译中。
  • 挂起一个任务可能会影响系统的实时性,因此需要谨慎使用。
  • 挂起一个任务不会释放它占用的资源,例如内存和堆栈。
  • 挂起一个任务不会影响其他任务的执行,但是需要注意不要永久挂起一个任务,因为它可能持有重要的资源或需要定期执行。

用法示例:

以下是一个使用 vTaskSuspend 的示例:

void vTaskFunction(void *pvParameters)
{
    for (;;)
    {
        // 任务代码
    }
}

void vAFunction(void)
{
    TaskHandle_t xHandle;

    // 创建一个任务,并存储句柄
    xTaskCreate(vTaskFunction, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle);

    // ...

    // 使用句柄挂起创建的任务
    vTaskSuspend(xHandle);

    // ...

    // 创建的任务在这段时间内不会运行,除非
    // 另一个任务调用 vTaskResume( xHandle )。

    // ...

    // 挂起我们自己
    vTaskSuspend(NULL);

    // 除非另一个任务调用 vTaskResume 并使用我们的句柄作为参数,
    // 否则我们无法到达这里。
}

在这个例子中,vAFunction 函数创建了一个任务,并获取了它的句柄 xHandle。然后,它使用 vTaskSuspend 来挂起任务。如果传递 NULLvTaskSuspend,它将挂起调用任务(即 vAFunction 函数中的当前任务)。

挂起和恢复任务:

  • 挂起任务通常用于调试或当任务不再需要执行时。
  • 恢复任务通常由另一个任务或中断服务例程执行,使用 vTaskResume 函数。

 (6)vTaskResume:

vTaskResume 是 FreeRTOS 提供的一个函数,用于恢复之前被挂起的任务。这个函数可以使得因为一次或多次调用 vTaskSuspend() 而停止执行的任务重新获得 CPU 时间。

函数原型:

void vTaskResume( TaskHandle_t xTaskToResume );

参数:

  • xTaskToResume:要恢复的任务的句柄。

功能:

  • vTaskResume 用于恢复一个已经被挂起的任务。
  • 无论任务被挂起了一次还是多次,只需要调用一次 vTaskResume 就可以使其恢复运行。

注意事项:

  • 在使用 vTaskResume 之前,确保在 FreeRTOSConfig.h 中定义了 INCLUDE_vTaskSuspend 为 1,以确保函数被包含在编译中。
  • 恢复一个任务不保证立即执行,任务的实际执行时间取决于任务的优先级和调度器的状态。
  • 如果任务被挂起并且持有重要的资源,恢复该任务可能对系统的实时性有重要影响。

用法示例:

以下是一个使用 vTaskResume 的示例:

void vTaskFunction(void *pvParameters)
{
    for (;;)
    {
        // 任务代码
    }
}

void vAFunction(void)
{
    TaskHandle_t xHandle;

    // 创建一个任务,并存储句柄
    xTaskCreate(vTaskFunction, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle);

    // ...

    // 使用句柄挂起创建的任务
    vTaskSuspend(xHandle);

    // ...

    // 创建的任务在这段时间内不会运行,除非
    // 另一个任务调用 vTaskResume( xHandle )。

    // ...

    // 恢复被挂起的任务
    vTaskResume(xHandle);

    // 被挂起的任务将再次获得微控制器的处理时间
    // 根据其在系统中的优先级。
}

在这个例子中,vAFunction 函数创建了一个任务,并获取了它的句柄 xHandle。然后,它使用 vTaskSuspend 来挂起任务。在某个时刻,它使用 vTaskResume 来恢复任务,使得任务可以重新获得 CPU 时间并继续执行。

挂起和恢复任务:

  • 挂起和恢复任务是管理任务执行流的两种有用机制,特别是在需要临时停止任务或在任务间同步时。
  • 这些操作应该谨慎使用,以避免死锁或不必要的性能开销。

(7)xTaskResumeFromISR:

xTaskResumeFromISR 是 FreeRTOS 提供的一个函数,它允许从中断服务例程(ISR)中恢复一个被挂起的任务。这个函数是 vTaskResume 的 ISR 安全版本,可以在中断上下文中调用。

函数原型:

BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume );

参数:

  • xTaskToResume:要恢复的任务的句柄。

返回值:

  • 如果恢复任务导致上下文切换,则返回 pdTRUE,否则返回 pdFALSE。ISR 使用此信息来确定 ISR 之后是否需要进行上下文切换。

功能:

  • xTaskResumeFromISR 用于从 ISR 中恢复一个被挂起的任务。
  • 与 vTaskResume 相比,xTaskResumeFromISR 可以安全地在中断上下文中使用,因为它是被设计为与 FreeRTOS 的中断锁定机制兼容的。

注意事项:

  • 在 FreeRTOSConfig.h 中,INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 宏必须定义为 1,才能使用 xTaskResumeFromISR 函数。
  • xTaskResumeFromISR 通常被视为“危险”函数,因为它的操作未被锁定,如果中断可能在任务被挂起之前到达,可能会导致中断丢失。因此,它不应该用于同步任务与中断。
  • 为了避免这种可能性,可以使用信号量或者直达任务通知(direct task notifications)。

用法示例:

以下是一个使用 xTaskResumeFromISR 的示例:

TaskHandle_t xHandle;

void vAFunction(void)
{
    // 创建一个任务,并存储句柄
    xTaskCreate(vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle);

    // ... 其他代码 ...
}

void vTaskCode(void *pvParameters)
{
    // 这个任务被挂起和恢复
    for (;;)
    {
        // ... 执行一些功能 ...

        // 任务挂起自己
        vTaskSuspend(NULL);

        // 任务现在被挂起,所以除非 ISR 恢复它,否则不会到达这里
    }
}

void vAnExampleISR(void)
{
    BaseType_t xYieldRequired;

    // 恢复被挂起的任务
    xYieldRequired = xTaskResumeFromISR(xHandle);

    // 根据需要切换上下文,所以 ISR 返回到不同的任务
    // 注意:这如何完成取决于你使用的端口。检查你的端口的文档和示例。
    portYIELD_FROM_ISR(xYieldRequired);
}

在这个例子中,vAFunction 函数创建了一个任务,并获取了它的句柄 xHandle。然后,在 ISR vAnExampleISR 中,使用 xTaskResumeFromISR 来恢复任务,并根据返回值决定是否需要在 ISR 之后进行上下文切换。

上下文切换:

  • xTaskResumeFromISR 返回的值用于确定是否需要在 ISR 结束后进行上下文切换。如果返回 pdTRUE,则调用 portYIELD_FROM_ISR 来请求上下文切换。

 (8)xTaskAbortDelay

xTaskAbortDelay 是 FreeRTOS 提供的一个函数,它用于强制一个正在延迟或阻塞状态的任务立即离开阻塞状态,并进入就绪状态。这个函数可以用于取消任务的 vTaskDelayvTaskDelayUntilulTaskNotifyTakexSemaphoreTake 等阻塞调用。

函数原型:

BaseType_t xTaskAbortDelay( TaskHandle_t xTask );

参数:

  • xTask:要强制退出阻塞状态的任务的句柄。

返回值:

  • BaseType_t:如果操作成功,返回 pdPASS;如果任务不在阻塞状态,返回 pdFAIL

功能:

  • xTaskAbortDelay 可以使任务立即退出延迟或阻塞状态,即使它正在等待的事件还没有发生或者指定的超时时间还没有结束。

注意事项:

  • 在 FreeRTOSConfig.h 中,INCLUDE_xTaskAbortDelay 宏必须定义为 1,才能使用 xTaskAbortDelay 函数。
  • 使用 xTaskAbortDelay 时要小心,因为它会强制任务退出它可能正在等待的重要事件或条件。

用法示例:

以下是一个使用 xTaskAbortDelay 的示例:

void vTaskFunction(void *pvParameters)
{
    TickType_t xDelayPeriod = 1000 / portTICK_PERIOD_MS;
    for (;;)
    {
        // 任务执行一些工作...

        // 任务进入延迟状态
        vTaskDelay(xDelayPeriod);

        // 任务执行更多工作...
    }
}

void vSomeOtherFunction(void)
{
    TaskHandle_t xTaskHandle;

    // 创建任务并获取句柄
    xTaskCreate(vTaskFunction, "Task", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTaskHandle);

    // ...

    // 假设我们需要在某个时刻强制任务退出延迟状态
    if (xTaskAbortDelay(xTaskHandle) == pdPASS)
    {
        // 任务成功退出延迟状态
    }
    else
    {
        // 任务不在延迟状态,或者任务句柄无效
    }

    // ...
}

在这个例子中,vTaskFunction 是一个任务函数,它在执行一些工作后会调用 vTaskDelay 进入延迟状态。在 vSomeOtherFunction 函数中,我们使用 xTaskAbortDelay 来强制任务退出延迟状态。如果任务成功退出延迟状态,xTaskAbortDelay 返回 pdPASS;如果任务不在延迟状态或者句柄无效,则返回 pdFAIL

 (9)uxTaskPriorityGetFromISR:

uxTaskPriorityGetFromISR 是 FreeRTOS 提供的一个函数,它允许从中断服务例程(ISR)中安全地获取任务的优先级。这个函数是 uxTaskPriorityGet 的 ISR 安全版本,可以在中断上下文中调用。

函数原型:

UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask );

参数:

  • xTask:待查询的任务的句柄。如果传递 NULL,则返回调用此函数的中断服务例程的优先级。

返回值:

  • 返回指定任务的优先级。

功能:

  • uxTaskPriorityGetFromISR 用于在中断服务程序中获取任务的优先级。
  • 这个函数是 ISR 安全的,意味着它不会调用任何可能会被中断锁定机制阻止的 API。

注意事项:

  • 在 FreeRTOSConfig.h 中,INCLUDE_uxTaskPriorityGet 宏必须定义为 1,才能使用 uxTaskPriorityGetFromISR 函数。
  • 与 uxTaskPriorityGet 相比,uxTaskPriorityGetFromISR 可以在中断上下文中安全使用,而 uxTaskPriorityGet 则不能。

用法示例:

以下是一个使用 uxTaskPriorityGetFromISR 的示例:

void vTaskFunction(void *pvParameters)
{
    for (;;)
    {
        // 任务代码
    }
}

void vAnExampleISR(void)
{
    UBaseType_t uxPriority;
    TaskHandle_t xTaskHandle;

    // 创建一个任务,并存储句柄
    xTaskCreate(vTaskFunction, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTaskHandle);

    // ...

    // 在 ISR 中获取任务的优先级
    uxPriority = uxTaskPriorityGetFromISR(xTaskHandle);

    // 如果我们传递 NULL,我们可以得到调用此 ISR 的任务的优先级
    // uxPriority = uxTaskPriorityGetFromISR(NULL);
}

在这个例子中,vAnExampleISR 是一个中断服务例程,它使用 uxTaskPriorityGetFromISR 来获取一个任务的优先级。如果传递 NULLuxTaskPriorityGetFromISR,它将返回调用中断服务例程的任务的优先级。

(10)uxTaskBasePriorityGet:

uxTaskBasePriorityGet 是 FreeRTOS 提供的一个函数,用于获取任务的基础优先级。基础优先级是指任务在没有因为互斥锁(mutexes)或其他原因而继承其他任务优先级时的原始优先级。

函数原型:

UBaseType_t uxTaskBasePriorityGet( const TaskHandle_t xTask );

参数:

  • xTask:待查询任务的句柄。如果传递 NULL,则返回调用此函数的任务的基础优先级。

返回值:

  • 返回指定任务的基础优先级。

功能:

  • uxTaskBasePriorityGet 用于获取任务的基础优先级,这是任务在没有继承其他优先级时的原始优先级。

注意事项:

  • 在 FreeRTOSConfig.h 中,INCLUDE_uxTaskPriorityGet 宏必须定义为 1,才能使用 uxTaskBasePriorityGet 函数。
  • 如果你的应用程序使用了互斥锁,configUSE_MUTEXES 宏也必须定义为 1。
  • 基础优先级的概念主要用于处理优先级反转问题。当一个高优先级任务持有一个互斥锁,而一个低优先级任务需要这个互斥锁时,可能会发生优先级反转。为了防止这种情况,低优先级任务可以临时提高其优先级(优先级继承),这样它就可以在不等待高优先级任务释放互斥锁的情况下继续执行。

用法示例:

以下是一个使用 uxTaskBasePriorityGet 的示例:

void vTaskFunction(void *pvParameters)
{
    // 任务代码
}

void vAFunction(void)
{
    TaskHandle_t xHandle;

    // 创建一个任务,并存储句柄
    xTaskCreate(vTaskFunction, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle);

    // ...

    // 获取并打印创建的任务的基础优先级
    UBaseType_t uxBasePriority = uxTaskBasePriorityGet(xHandle);
    printf("Task Base Priority: %lu\n", uxBasePriority);

    // 如果我们传递 NULL,我们可以得到调用此函数的任务的基础优先级
    UBaseType_t uxOurBasePriority = uxTaskBasePriorityGet(NULL);
    printf("Current Task Base Priority: %lu\n", uxOurBasePriority);
}

在这个例子中,vAFunction 函数创建了一个任务,并获取了它的句柄 xHandle。然后,它使用 uxTaskBasePriorityGet 来获取任务的基础优先级,并打印出来。如果传递 NULLuxTaskBasePriorityGet,它将返回调用任务的基础优先级。

(11)uxTaskBasePriorityGetFromISR:

uxTaskBasePriorityGetFromISR 是 FreeRTOS 提供的一个函数,它允许从中断服务例程(ISR)中安全地获取任务的基础优先级。这个函数是 uxTaskBasePriorityGet 的 ISR 安全版本,可以在中断上下文中调用。

函数原型:

UBaseType_t uxTaskBasePriorityGetFromISR( const TaskHandle_t xTask );

参数:

  • xTask:待查询任务的句柄。如果传递 NULL,则返回调用此函数的中断服务例程的任务的基础优先级。

返回值:

  • 返回指定任务的基础优先级。

功能:

  • uxTaskBasePriorityGetFromISR 用于在中断服务程序中获取任务的基础优先级。
  • 基础优先级是指任务在没有因为互斥锁(mutexes)或其他原因而继承其他任务优先级时的原始优先级。

注意事项:

  • 在 FreeRTOSConfig.h 中,INCLUDE_uxTaskPriorityGet 和 configUSE_MUTEXES 宏必须定义为 1,才能使用 uxTaskBasePriorityGetFromISR 函数。
  • 此函数可以安全地在中断上下文中使用,因为它不会调用任何可能会被中断锁定机制阻止的 API。

用法示例:

以下是一个使用 uxTaskBasePriorityGetFromISR 的示例:

void vTaskFunction(void *pvParameters)
{
    for (;;)
    {
        // 任务代码
    }
}

void vAnExampleISR(void)
{
    UBaseType_t uxBasePriority;
    TaskHandle_t xTaskHandle;

    // 创建一个任务,并存储句柄
    xTaskCreate(vTaskFunction, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTaskHandle);

    // ...

    // 在 ISR 中获取任务的基础优先级
    uxBasePriority = uxTaskBasePriorityGetFromISR(xTaskHandle);

    // 如果我们传递 NULL,我们可以得到调用此 ISR 的任务的基础优先级
    // uxBasePriority = uxTaskBasePriorityGetFromISR(NULL);
}

在这个例子中,vAnExampleISR 是一个中断服务例程,它使用 uxTaskBasePriorityGetFromISR 来获取一个任务的基础优先级。如果传递 NULLuxTaskBasePriorityGetFromISR,它将返回调用中断服务例程的任务的基础优先级。

 


原文地址:https://blog.csdn.net/The_xz/article/details/142423963

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!