当前位置: 首页 > news >正文

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,它将返回调用中断服务例程的任务的基础优先级。

 

http://www.lryc.cn/news/444219.html

相关文章:

  • Go语言现代web开发14 协程和管道
  • Llama3.1的部署与使用
  • Java/Spring项目的包开头为什么是com?
  • 深度学习自编码器 - 随机编码器和解码器篇
  • Spring IoC DI
  • [数据集][目标检测]无人机飞鸟检测数据集VOC+YOLO格式6647张2类别
  • Vue 中 watch 的使用方法及注意事项
  • 情指行一体化平台建设方案和必要性-———未来之窗行业应用跨平台架构
  • 窗口框架frame(HTML前端)
  • 51单片机——数码管
  • `re.compile(r“(<.*?>)“)` 如何有效地从给定字符串中提取出所有符合 `<...>` 格式的引用
  • 算法打卡:第十一章 图论part01
  • 为C#的PetaPoco组件增加一个批量更新功能(临时表模式)
  • Spring实战——入门讲解
  • MTK芯片机型的“工程固件” 红米note9 5G版资源预览 写入以及改写参数相关步骤解析
  • [Golang] Context
  • 【JAVA集合总结-壹】
  • Mysql梳理7——分页查询
  • 智能制造与工业互联网公益联播∣企企通副总经理杨华:AI的浪潮下,未来智慧供应链迭代方向
  • 《深度学习》—— 卷积神经网络(CNN)的简单介绍和工作原理
  • 数据结构:线性表
  • Ansible PlayBook实践案例
  • Tomcat后台弱口令部署war包
  • 胤娲科技:DeepMind的FermiNet——带你穿越“薛定谔的早餐桌”
  • 迅为iTOP-STM32MP157开发板板载4G接口(选配)_千兆以太网_WIFI蓝牙模块_HDMI_CAN_RS485_LVDS接口等
  • Android Choreographer 监控应用 FPS
  • 关于 mybatis-plus-boot-starter 与 mybatis-spring-boot-starter 的错误
  • NLP 文本分类任务核心梳理
  • k8s中pod的创建过程和阶段状态
  • NSSCTF刷题篇1