任务挂起和恢复的区别
挂起还能被恢复,删除任务后无法恢复。
带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所管理的最高优先级
首先打开宏
设置NVIC分组为4
/**
****************************************************************************************************
* @file freertos.c
* @author 正点原子团队(ALIENTEK)
* @version V1.4
* @date 2022-01-04
* @brief FreeRTOS 移植实验
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
****************************************************************************************************
* @attention
*
* 实验平台:正点原子 F407电机开发板
* 在线视频:www.yuanzige.com
* 技术论坛:www.openedv.com
* 公司网址:www.alientek.com
* 购买地址:openedv.taobao.com
*
****************************************************************************************************
*/
#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_handler;
void start_task( void * pvParameters );
#define TASK1_PRIO 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handler;
void task1( void * pvParameters );
#define TASK2_PRIO 3
#define TASK2_STACK_SIZE 128
TaskHandle_t task2_handler;
void task2( void * pvParameters );
#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();
}
void task1( void * pvParameters )
{
uint32_t task1_num=0;
while(1)
{
task1_num++;
printf("task1_num= %d \n",task1_num);
LED0_TOGGLE();
vTaskDelay(500);
}
}
void task2( void * pvParameters )
{
uint32_t task2_num=0;
while(1)
{
task2_num++;
printf("task2_num= %d \n",task2_num);
LED1_TOGGLE();
vTaskDelay(500);
}
}
void task3( void * pvParameters )
{
//静态变量在程序运行期间只会被初始化一次,即使经过多次函数调用或程序执行。因此,在程序下次运行时,静态变量的值将保持上一次程序运行结束时的值,并不会重新赋初值。
//如果未显式指定初始值,则静态变量将根据其类型自动初始化为默认值。例如,静态变量 uint8_t key_up 初始值为 0。
static uint8_t key =0;
while(1)
{
key = key_scan(0);
if(key==KEY0_PRES)
{
/*挂起任务1*/
vTaskSuspend(task1_handler);
}
else if(key==KEY1_PRES)
{
/*恢复任务1*/
vTaskResume(task1_handler);
}
vTaskDelay(10);
}
}
外部中断触发函数
void KEY2_INT_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(KEY2_INT_GPIO_PIN); /* 调用中断处理公用函数 清除KEY2所在中断线 的中断标志位,中断下半部在HAL_GPIO_EXTI_Callback执行 */
__HAL_GPIO_EXTI_CLEAR_IT(KEY2_INT_GPIO_PIN); /* HAL库默认先清中断再处理回调,退出时再清一次中断,避免按键抖动误触发 */
}
/**
* @brief 中断服务程序中需要做的事情
* 在HAL库中所有的外部中断服务函数都会调用此函数
* @param GPIO_Pin:中断引脚号
* @retval 无
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(20); /* 消抖 */
BaseType_t xYieldRequired;
if (KEY2 == 0)
{
xYieldRequired = xTaskResumeFromISR(task1_handler);
}
if(xYieldRequired==pdTRUE)
{
portYIELD_FROM_ISR(xYieldRequired );
}
}
/**
* @brief 外部中断初始化程序
* @param 无
* @retval 无
*/
void extix_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
key_init();
gpio_init_struct.Pin = KEY2_INT_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_IT_FALLING; /* 下降沿触发 */
gpio_init_struct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(KEY2_INT_GPIO_PORT, &gpio_init_struct); /* KEY2配置为下降沿触发中断 */
HAL_NVIC_SetPriority(KEY2_INT_IRQn, 6,0); /* 抢占2,子优先级2 */
HAL_NVIC_EnableIRQ(KEY2_INT_IRQn); /* 使能中断线2 */
}
注意NVIC配置HAL_NVIC_SetPriority(KEY2_INT_IRQn, 6,0);优先级要在5-15之间
官方参考链接
https://www.freertos.org/zh-cn-cmn-s/taskresumefromisr.html