FreeRTOS保姆级教程(以STM32为例)—任务创建和任务控制API说明
目录
(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
来检查任务的优先级是否发生了变化。如果传递 NULL
给 uxTaskPriorityGet
,它将返回调用任务(即 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
来提高任务的优先级。如果传递 NULL
给 vTaskPrioritySet
,它将提高调用任务(即 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
来挂起任务。如果传递 NULL
给 vTaskSuspend
,它将挂起调用任务(即 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 提供的一个函数,它用于强制一个正在延迟或阻塞状态的任务立即离开阻塞状态,并进入就绪状态。这个函数可以用于取消任务的 vTaskDelay
、vTaskDelayUntil
、ulTaskNotifyTake
、xSemaphoreTake
等阻塞调用。
函数原型:
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
来获取一个任务的优先级。如果传递 NULL
给 uxTaskPriorityGetFromISR
,它将返回调用中断服务例程的任务的优先级。
(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
来获取任务的基础优先级,并打印出来。如果传递 NULL
给 uxTaskBasePriorityGet
,它将返回调用任务的基础优先级。
(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
来获取一个任务的基础优先级。如果传递 NULL
给 uxTaskBasePriorityGetFromISR
,它将返回调用中断服务例程的任务的基础优先级。
原文地址:https://blog.csdn.net/The_xz/article/details/142423963
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!