FreeRTOS-任务挂起和恢复
一、任务挂起及恢复介绍
- 任务挂起是指将某个任务从就绪态或运行态中移除,并将其置于挂起态,让它暂时不再参与调度,不分配CPU时间片,直到它被恢复
- 挂起任务时,它会立即停止运行,直到该任务被显式恢复。挂起任务用于节省CPU资源或防止某些任务在特定条件下继续执行
挂起任务可以恢复,而删除任务无法恢复
- 任务恢复是指将挂起的任务从挂起态恢复到就绪态,使其可以再次参与调度,并根据其优先级来决定何时运行
- 任务恢复通常是在外部条件发生变化、或另一个条件、ISR(中断服务程序)通知当前任务可以继续工作时使用
- 下面是任务挂起和恢复的API函数
vTaskSuspend(TaskHandle_t xTaskToSuspend);//挂起任务,参数是待挂起任务句柄
vTaskResume(TaskHandle_t xTaskToResume);//恢复被挂起的任务,参数是待恢复任务句柄
BaseType_t vTaskResumeFromISR(TaskHandle_t xTaskToResume);//在中断中恢复被挂起的任务,参数是任务句柄//FromISR表示在中断函数中专用的API函数
- 任务挂起操作时,需要将宏INCLUDE_vTaskSuspend配置为1,当传入参数为NULL,表示挂起任务自身
- 任务恢复操作时,需要将宏INCLUDE_vTaskSuspend配置为1,无论任务被挂起多少次,调用一次vTaskResume()即可恢复,进入就绪态
- 中断中恢复任务操作时,需要将宏INCLUDE_vTaskSuspend和INCLUDE_xTaskResumeFromISR配置为1。返回值为pdTRUE:任务恢复后需要进行任务切换(恢复的任务优先级高)和pdFALSE:任务恢复后不需要进行任务切换,专用于中断服务函数中
- 中断服务程序中要调用FreeRTOS的API函数时,中断优先级不能高于FreeRTOS所管理的最高优先级
- 例:设置可调用FreeRTOS API的最高优先级为为4,且系统有8个可配置中断优先级,从0-7,数字越小,中断优先级越高,那么优先级4,5,6,7的中断可以调用API函数,0,1,2,3的中断不可以调用API函数
二、实战编程
- 创建四个任务,Start_task(用来创建其他三个任务)、task1(LED0每500ms闪烁一次)、task2(LED1每500ms闪烁一次)、task3(KEY0按下,挂起task1,按下KEY1在任务中恢复task1)
#define configSUPPORT_DYNAMIC_ALLOCATION 1//动态创建任务宏定义配置
#define INCLUDE_vTaskSuspend 1//挂起/恢复任务宏定义配置
//start_task参数宏定义
#define START_TASK_STACK_SIZE 128//堆栈大小
#define START_TASK_PRIO 1//任务优先级
TaskHandle_t start_task_handle; //任务句柄
//task1参数宏定义
#define TASK1_STACK_SIZE 128//堆栈大小
#define TASK1_PRIO 2//任务优先级
TaskHandle_t task1_handle; //任务句柄
//task2参数宏定义
#define TASK2_STACK_SIZE 128//堆栈大小
#define TASK2_PRIO 3//任务优先级
TaskHandle_t task2_handle; //任务句柄
//task3参数宏定义
#define TASK3_STACK_SIZE 128//堆栈大小
#define TASK3_PRIO 4//任务优先级
TaskHandle_t task3_handle; //任务句柄
//task1任务函数:LED0每500ms闪烁一次
void task1( void * pvParameters )
{
while(1)
{
LED0_Turn();//LED0反转
vTaskDelay(500);//自带延时函数
}
}
//task2任务函数:LED1每500ms闪烁一次
void task2( void * pvParameters )
{
while(1)
{
LED0_Turn();//LED1反转
vTaskDelay(500);//自带延时函数
}
}
//task3任务函数:判断按键按下,KEY0按下挂起task1,KEY1按下恢复task1
void task3( void * pvParameters )
{
uint8_t KeyNum = 0;
while(1)
{
KeyNum = Key_GetNum();//获取按键键码
if(KeyNum == 0)//KEY0按下
{
vTaskSuspend(task1_handle);//挂起task1
}
else if(KeyNum == 1)//KEY1按下
{
vTaskResume(task1_handle);//恢复task1
}
vTaskDelay(10);//延时10ms,给了task1和task2机会
}
}
//Start_task任务函数
void Start_task( void * pvParameters )
{
taskENTER_CRITICAL();//进入临界区
//创建任务1
xTaskCreate(task1,//任务函数
"task1",//任务名称
TASK1_STACK_SIZE,//堆栈大小/字
NULL,//入口参数没有
TASK1_PRIO,//优先级
&task1_handle//任务句柄
);
//创建任务2
xTaskCreate(task2,//任务函数
"task2",//任务名称
TASK2_STACK_SIZE,//堆栈大小/字
NULL,//入口参数没有
TASK2_PRIO,//优先级
&task2_handle//句柄
);
//创建任务3
xTaskCreate(task3,//任务函数
"task3",//任务名称
TASK3_STACK_SIZE,//堆栈大小/字
NULL,//入口参数没有
TASK3_PRIO,//优先级
&task3_handle//句柄
);
vTaskDelete(start_task_handle);
//删除自身任务Start_task,start_task_handle或NULL都可以
taskEXIT_CRITICAL();//退出临界区
}
//FreeRTOS入口函数,程序从此处开始执行
void freertos_demo()
{
xTaskCreate(Start_task,//任务函数
"Start_task",//任务名称
START_TASK_STACK_SIZE,//堆栈大小/字
NULL,//入口参数没有
START_TASK_PRIO,//优先级
&start_task_handle//句柄
);//创建Start任务
vTaskStartScheduler();//开启任务调度器,开启执行Start任务,创建task123
}