1.任务的挂起与恢复的API函数
API函数 | 描述 |
---|---|
vTaskSuspend() | 挂起任务 |
vTaskResume() | 恢复被挂起的任务 |
xTaskResumeFromISR() | 在中断中恢复被挂起的任务 |
挂起:挂起任务类似暂停,可恢复; 删除任务,无法恢复。
恢复:恢复被挂起的任务
“FromISR”:带FromISR后缀是在中断函数中专用的API函数
任务挂起函数介绍
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
形参 | 描述 |
---|---|
xTaskToSuspend | 待挂起任务的任务句柄 |
此函数用于挂起任务,使用时需将宏 INCLUDE_vTaskSuspend 配置为 1。
无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复 。
当传入的参数为NULL,则代表挂起任务自身(当前正在运行的任务)
任务恢复函数介绍(任务中恢复)
任务中恢复被挂起函数:void vTaskResume(TaskHandle_t xTaskToResume)
形参 | 描述 |
xTaskToResume | 待恢复任务的任务句柄 |
使用该函数注意宏:INCLUDE_vTaskSuspend必须定义为 1
任务无论被 vTaskSuspend() 挂起多少次,只需在任务中调用 vTakResume() 恢复一次,就可以继续运行。且被恢复的任务会进入就绪态!
任务恢复函数介绍(中断中恢复)
中断中恢复被挂起函数: BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
形参 | 描述 |
---|---|
xTaskToResume | 待恢复任务的任务句柄 |
函数:xTaskResumeFromISR返回值描述如下:
返回值 | 描述 |
---|---|
pdTRUE | 任务恢复后需要进行任务切换 |
pdFALSE | 任务恢复后不需要进行任务切换 |
使用该函数注意宏:INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1
该函数专用于中断服务函数中,用于解挂被挂起任务
中断服务程序中要调用freeRTOS的API函数则中断优先级不能高于FreeRTOS所管理的最高优先级
2.任务挂起和恢复API函数解析
任务挂起函数内部实现
1、获取所要挂起任务的控制块
通过传入的任务句柄,判断所需要挂起哪个任务,NULL代表挂起自身
2、移除所在列表
将要挂起的任务从相应的状态列表和事件列表中移除(就绪或阻塞列表)
3、插入挂起任务列表
将待挂起任务的任务状态列表项插入到挂起态任务列表末尾
4、判断任务调度器是否运行
在运行,更新下一次阻塞时间,防止被挂起任务为下一次阻塞超时任务
5、判断待挂起任务是否为当前任务
如果挂起的是任务自身,且调度器正在运行,需要进行一次任务切换
调度器没有运行,判断挂起任务数是否等于任务总数,是:当前控制块赋值为NULL,否:寻找下一个最高优先级任务
任务恢复函数内部实现
1、恢复任务不能是正在运行任务
2、判断任务是否在挂起列表中
是:就会将该任务在挂起列表中移除, 将该任务添加到就绪列表中
3、判断恢复任务优先级
判断恢复的任务优先级是否大于当前正在运行的 是的话执行任务切换
3.任务挂起与恢复实验
将设计四个任务:
start_task:用来创建其他的三个任务
task1:实现LED0每500ms闪烁一次
task2:实现LED1每500ms闪烁一次
task3:判断按键按下逻辑,KEY0按下,挂起task1,按下KEY1在任务中恢复task1
按下KEY2,在中断中恢复task1(外部中断线实现)
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handler;
void start_task( void * pvParameters );
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1( void * pvParameters );
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2( void * pvParameters );
/* TASK3 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK3_PRIO 4
#define TASK3_STACK_SIZE 128
TaskHandle_t task3_handler;
void task3( void * pvParameters );
/******************************************************************************************************/
/**
* @brief FreeRTOS例程入口函数
* @param 无
* @retval 无
*/
void freertos_demo(void)
{
xTaskCreate((TaskFunction_t ) start_task,
(char * ) "start_task",
(configSTACK_DEPTH_TYPE ) START_TASK_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(TaskHandle_t * ) &start_task_handler );
vTaskStartScheduler();
}
void start_task( void * pvParameters )
{
taskENTER_CRITICAL(); /* 进入临界区 */
xTaskCreate((TaskFunction_t ) task1,
(char * ) "task1",
(configSTACK_DEPTH_TYPE ) TASK1_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(TaskHandle_t * ) &task1_handler );
xTaskCreate((TaskFunction_t ) task2,
(char * ) "task2",
(configSTACK_DEPTH_TYPE ) TASK2_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(TaskHandle_t * ) &task2_handler );
xTaskCreate((TaskFunction_t ) task3,
(char * ) "task3",
(configSTACK_DEPTH_TYPE ) TASK3_STACK_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK3_PRIO,
(TaskHandle_t * ) &task3_handler );
vTaskDelete(NULL);
taskEXIT_CRITICAL(); /* 退出临界区 */
}
/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
uint32_t task1_num = 0;
while(1)
{
printf("task1_num:%d\r\n",++task1_num);
LED0_TOGGLE();
vTaskDelay(500);
}
}
/* 任务二,实现LED1每500ms翻转一次 */
void task2( void * pvParameters )
{
uint32_t task2_num = 0;
while(1)
{
printf("task2_num:%d\r\n",++task2_num);
LED1_TOGGLE();
vTaskDelay(500);
}
}
/* 任务三,判断按键KEY0,按下KEY0删除task1 */
void task3( void * pvParameters )
{
uint8_t key = 0;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
printf("挂起task1\r\n");
vTaskSuspend(task1_handler);
}else if(key == KEY1_PRES)
{
printf("在任务中恢复task1\r\n");
vTaskResume(task1_handler);
}
vTaskDelay(10);
}
}
本文参考正点原子手把手教你学FreeRTOS实时系统视频学习