任务的挂起与恢复
一、API函数介绍
二、编程实现
实验目的:学会使用 vTaskSuspend()、vTaskResume()、xTaskResumeFromISR()
实验设计内容:设计四个任务:start_task、task1、task2、task3
task1:实现LED0每500ms闪烁一次
task2:实现LED1每500ms闪烁一次
task3:判断按键按下逻辑,KEY0被按下,挂起task1,按下KEY1在任务中恢复task1,按下KEY_WK_UP,在中断中恢复task1(外部中断线实现)
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_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();
}
// Task to be created.
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(start_task_handler);
taskEXIT_CRITICAL();
}
//实现LED0 每500ms翻转一次
void task1( void * pvParameters )
{
while(1)
{
printf ("task1正在运行!!!\r\n");
LED0_TOGGLE();
vTaskDelay(500);
}
}
//实现LED1 每500ms翻转一次
void task2( void * pvParameters )
{
while(1)
{
printf ("task2正在运行!!!\r\n");
LED1_TOGGLE();
vTaskDelay(500);
}
}
//判断按键key0是否按下,按下则删除task1
void task3( void * pvParameters )
{
uint8_t key = 0;
while(1)
{
printf ("task3正在运行!!!\r\n");
key = key_scan(0);
if(key == KEY0_PRES)
{
vTaskSuspend(task1_handler);
}
else if(key == KEY1_PRES)
{
vTaskResume(task1_handler);
}
vTaskDelay(10);
}
}
exti.c
/**
****************************************************************************************************
* @file exti.c
* @author 正点原子团队(ALIENTEK)
* @version V1.0
* @date 2020-04-19
* @brief 外部中断 驱动代码
* @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
****************************************************************************************************
* @attention
*
* 实验平台:正点原子 MiniSTM32 V4开发板
* 在线视频:www.yuanzige.com
* 技术论坛:www.openedv.com
* 公司网址:www.alientek.com
* 购买地址:openedv.taobao.com
*
* 修改说明
* V1.0 20200420
* 第一次发布
*
****************************************************************************************************
*/
#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_demo.h"
#include "FreeRTOS.h"
#include "task.h"
/**
* @brief KEY0 外部中断服务程序
* @param 无
* @retval 无
*/
extern TaskHandle_t task1_handler;
/**
* @brief KEY1 外部中断服务程序
* @param 无
* @retval 无
*/
/**
* @brief WK_UP 外部中断服务程序
* @param 无
* @retval 无
*/
void WKUP_INT_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(WKUP_INT_GPIO_PIN); /* 调用中断处理公用函数 清除KEY1所在中断线 的中断标志位,中断下半部在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 xYiedRequired ;
case WKUP_INT_GPIO_PIN:
if (WK_UP == 1)
{
xYiedRequired = xTaskResumeFromISR(task1_handler);
if(xYiedRequired == pdTRUE)
{
portYIELD_FROM_ISR(xYiedRequired);
}
}
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); /* 抢占2,子优先级2 */
HAL_NVIC_EnableIRQ(WKUP_INT_IRQn); /* 使能中断线0 */
}