一、任务挂起和恢复的API函数
1、任务挂起函数介绍
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
此函数用于挂起任务,使用时需将宏 INCLUDE_vTaskSuspend 配置为 1。
无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复 。
注意:当传入的参数为NULL,则代表挂起任务自身(当前正在运行的任务)
2、任务恢复函数介绍(任务中恢复)
void vTaskResume(TaskHandle_t xTaskToResume)
使用该函数注意宏:INCLUDE_vTaskSuspend必须定义为 1
注意:任务无论被 vTaskSuspend() 挂起多少次,只需在任务中调用 vTakResume() 恢复一次,就可以继续运行。且被恢复的任务会进入就绪态!
3、任务恢复函数介绍(中断中恢复)
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
使用该函数注意宏:INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1
该函数专用于中断服务函数中,用于解挂被挂起任务
注意:中断服务程序中要调用freeRTOS的API函数则中断优先级不能高于FreeRTOS所管理的最高优先级
二、任务挂起与恢复实验
实验设计:将设计四个任务:start_task、task1、task2、task3
四个任务的功能如下:
1、main.c
在main.c中,初始化使用到的各个外设,再调用freertos_demo()函数即可,代码如下:
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
//#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./MALLOC/malloc.h"
#include "./BSP/EXTI/exti.h"
#include "freertos_demo.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
// usmart_dev.init(72); /* 初始化USMART */
led_init(); /* 初始化LED */
// lcd_init(); /* 初始化LCD */
extix_init(); /* 初始化外部中断按键 */
key_init(); /* 初始化按键 */
my_mem_init(SRAMIN); /* 初始化内部SRAM内存池 */
freertos_demo();
}
2、exti.c
在exti.c中,初始化外部中断按键wk_up,然后判断按键按下时,将任务1恢复,注意按键的中断抢占优先级只能在5-15中选择,并且在stm32f1xx_hal.c中修改中断分组函数为HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);即4位抢占优先级,0位子优先级。
代码如下:
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/EXTI/exti.h"
#include "FreeRTOS.h" //添加头文件
#include "task.h"
extern TaskHandle_t task1_hander;
/**
* @brief WK_UP 外部中断服务程序
* @param 无
* @retval 无
*/
void WKUP_INT_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(WKUP_INT_GPIO_PIN); /* 调用中断处理公用函数 清除KEY_UP所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行 */
__HAL_GPIO_EXTI_CLEAR_IT(WKUP_INT_GPIO_PIN); /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}
/**
* @brief 中断服务程序中需要做的事情
在HAL库中所有的外部中断服务函数都会调用此函数
* @param GPIO_Pin:中断引脚号
* @retval 无
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(20); /* 消抖 */
switch(GPIO_Pin)
{
BaseType_t xYieldRequired;
case WKUP_INT_GPIO_PIN:
if (WK_UP == 1)
{
xYieldRequired = xTaskResumeFromISR(task1_hander);//中断中恢复函数
printf("在中断中恢复task1\r\n");
}
if (xYieldRequired == pdTRUE) //需要进行任务切换
{
portYIELD_FROM_ISR(xYieldRequired);
}
break;
}
}
/**
* @brief 外部中断初始化程序
* @param 无
* @retval 无
*/
void extix_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
WKUP_GPIO_CLK_ENABLE(); /* WKUP时钟使能 */
gpio_init_struct.Pin = WKUP_INT_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_IT_RISING; /* 上升沿触发 */
gpio_init_struct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(WKUP_GPIO_PORT, &gpio_init_struct); /* WKUP配置为下降沿触发中断 */
HAL_NVIC_SetPriority(WKUP_INT_IRQn, 5, 0); /* 抢占5,子优先级0 */
HAL_NVIC_EnableIRQ(WKUP_INT_IRQn); /* 使能中断线0 */
}
3、freertos_demo.c
代码如下:
#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_TASK_STACK_SIZE 128
TaskHandle_t start_task_hander;
void start_task( void * pvParameters );
/* TASK1 任务配置 */
#define TASK1_PRIO 4
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_hander;
void task1( void * pvParameters );
/* TASK2 任务配置 */
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_hander;
void task2( void * pvParameters );
/* TASK3 任务配置 */
#define TASK3_PRIO 2
#define TASK3_STACK_SIZE 128
TaskHandle_t task3_hander;
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_hander);//任务句柄
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_hander);//任务句柄
xTaskCreate((TaskFunction_t ) task2,
(char * ) "task2",//任务名字
(configSTACK_DEPTH_TYPE ) TASK2_STACK_SIZE,//堆栈大小
(void * ) NULL,//入口参数
(UBaseType_t ) TASK2_PRIO,//任务优先级
(TaskHandle_t * ) &task2_hander);//任务句柄
xTaskCreate((TaskFunction_t ) task3,
(char * ) "task3",//任务名字
(configSTACK_DEPTH_TYPE ) TASK3_STACK_SIZE,//堆栈大小
(void * ) NULL,//入口参数
(UBaseType_t ) TASK3_PRIO,//任务优先级
(TaskHandle_t * ) &task3_hander);//任务句柄
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)
{
taskENTER_CRITICAL();
key = key_scan(0);
if (key == KEY0_PRES)
{
printf("挂起task1\r\n");
vTaskSuspend(task1_hander);//挂起任务1
}
else if (key == KEY1_PRES)
{
printf("任务中恢复task1\r\n");
vTaskResume(task1_hander);//恢复任务1
}
taskEXIT_CRITICAL();
vTaskDelay(1);
}
}