1 任务挂起与恢复的API函数
API函数 | 描述 |
vTaskSuspend() | 挂起任务 |
vTaskResume() | 恢复被挂起的任务 |
xTaskResumeFromISR() | 在中断中恢复被挂起的任务 |
挂起:挂起任务类似暂停,可恢复;删除任务,无法恢复
恢复:恢复被挂起的任务
FromISR:带FromISR后缀是在中断函数中专用的API函数
1.1 任务挂起函数
void vTaskSuspend(TaskHandle_t xTaskToSuspend) //xTaskToSuspend 待挂起任务的任务句柄
注意:
1)此函数用于挂起任务,使用时需将宏INCLUDE_vTaskSuspend配置为1
2)无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复
3)当传入的参数为NULL,则代表挂起任务自身(当前正在执行的任务)
1.2 任务恢复函数(任务中恢复)
void vTaskResume(TaskHandle_t xTaskToResume) //xTaskToResume 待恢复任务的任务句柄
注意:任务无论被 vTaskSuspend()挂起多少次,只需在任务中调用vTaskResume()恢复一次,就可以继续运行。且被恢复的任务会进入就绪态。
1.3任务恢复函数(中断中恢复)
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
//xTaskToResume待恢复任务的任务句柄
函数返回值描述如下:
返回值 | 描述 |
pdTRUE | 任务恢复后需要进行任务切换(就是恢复的任务优先级大于当前正在执行的任务) |
pdFALSE | 任务恢复后不需要进行任务切换 |
注意:
1)INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1。
2)该函数专用于中断服务函数中,用于解挂被挂起任务。
3)中断服务程序中调用FreeRTOS的API函数则中断优先级不能高于FreeRTOS所管理的最高优先级(FreeRTOS管理的优先级是5~15),如果中断优先级在0~4,比5~15中断优先级高,因此会报错。
4)任务优先级和中断优先级是有区别的,3)中的指的是中断优先级,任务优先级是数值越大,优先级越高;中断优先级是数值越小优先级越高。
使用中断恢复时需要更改:
* 都设置成抢占优先级,就是为了方便FreeRTOS方便管理
*抢占优先级最大设置为5
2 任务挂起与恢复实验
实验设计:将设计四个任务:start_task、task1、task2、task3
start_task :用来创建其他的三个任务
task1 :实现LED0每500ms闪烁一次
task2 :实现LED1每500ms闪烁一次
task3 :判断按键按下逻辑,KEY0按下,挂起task1,按下KEY1在任务中恢复task1
中断中:按下KEY2,在中断中恢复task1(外部中断线实现)
//在任务中恢复
#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
/******************************************************************************************************/
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1 /* 任务优先级 */
#define START_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; /* 任务句柄 */
void start_task(void *pvParameters); /* 任务函数 */
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task1Task_Handler; /* 任务句柄 */
void task1(void *pvParameters); /* 任务函数 */
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3 /* 任务优先级 */
#define TASK2_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task2Task_Handler; /* 任务句柄 */
void task2(void *pvParameters); /* 任务函数 */
/* TASK3 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK3_PRIO 4 /* 任务优先级 */
#define TASK3_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t Task3Task_Handler; /* 任务句柄 */
void task3(void *pvParameters); /* 任务函数 */
/******************************************************************************************************/
void freertos_demo(void)
{
xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */
(const char* )"start_task", /* 任务名称 */
(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */
(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */
vTaskStartScheduler();
}
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); /* 进入临界区 */
/* 创建任务1 */
xTaskCreate((TaskFunction_t )task1,
(const char* )"task1",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
/* 创建任务2 */
xTaskCreate((TaskFunction_t )task2,
(const char* )"task2",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
/* 创建任务3 */
xTaskCreate((TaskFunction_t )task3,
(const char* )"task3",
(uint16_t )TASK3_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK3_PRIO,
(TaskHandle_t* )&Task3Task_Handler);
vTaskDelete(StartTask_Handler); /* 删除开始任务 */
taskEXIT_CRITICAL(); /* 退出临界区 */
}
void task1(void *pvParameters)
{
uint32_t task1_num = 0;
while(1)
{
printf("task1_num:%d\r\n",++ task1_num);
LED0_TOGGLE(); /* LED0闪烁 */
vTaskDelay(500); /* 延时500ms */
}
}
void task2(void *pvParameters)
{
uint32_t task2_num = 0;
while(1)
{
printf("task2_num:%d\r\n",++task2_num);
LED1_TOGGLE(); /* LED0闪烁 */
vTaskDelay(500); /* 延时500ms */
}
}
/* 任务三:判断按键KEY0,按下KEY0删除task*/
void task3(void *pvParameters)
{
uint8_t key = 0;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
printf("挂起task1\r\n");
vTaskSuspend(Task1Task_Handler);
}
else if(key == KEY1_PRES)
{
printf("在任务中恢复task1\r\n");
vTaskResume(Task1Task_Handler);
}
vTaskDelay(10);
}
}
//在中断中恢复任务
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(20); /* 消抖 */
switch(GPIO_Pin)
{
BaseType_t xYieldRequired;
case KEY2_INT_GPIO_PIN:
if (KEY2 == 0)
{
xYieldRequired = xTaskResumeFromISR(Task1Task_Handler);
//xYieldRequired用取函数返回值
}
if (xYieldRequired == pdTRUE)
//判断任务是否需要切换
{
printf("在中断中恢复task1\r\n");
portYIELD_FROM_ISR(xYieldRequired);
//调用该函数实现任务切换
}
break;
default : break;
}
}