FreeRtos任务恢复与挂起
本篇内容分享的是FreeRtos中的任务恢复与挂起。
有时候我们需要将暂停某个任务的运行,过一段时间以后在重新运行。这个时候是要适应任务删除和重建的方法的话那么任务中变量保存的值肯定丢了!FreeRtos给我们提供了解决这种问题的方法,那就是任务的恢复与挂起,当莫个任务要停止运行一段时间的话就将这个任务挂起,当要重新运行这个任务的话就恢复这个任务的运行,FreeRtos的任务挂起与恢复API函数如下:
vTaskSuspend()函数
此函数用于将某个任务设置为挂起态,进入挂起态的任务永远都不会进入运行态。退出挂起态的唯一方法就是调用任务恢复函数 vTaskResume()xTaskResumeFromISR()
/*-----------------------函数原型-------------------*/
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
//参数为任务句柄
要挂起的任务的任务句柄,创建任务的时候会为每个任务分配一个任务句柄。如果使用函数 xTaskCreate()创建任务的话那么函数的参数pxCreatedTask 就是此任务的任务句柄,如果使用函数 xTaskCreateStatic()创建任务的话那么函数的返回值就是此任务的任务句柄。也可以通过函数 xTaskGetHandle()来根据任务名字来获取某个任务的任务句柄。
注意!如果参数为 NULL 的话表示挂起任务自己。
vTaskResume()
/*--------------------函数原型------------------*/
void vTaskResume( TaskHandle_t xTaskToResume )
//参数为任务句柄
将一个任务从挂起态恢复到就绪态,只有通过函数 vTaskSuspend()设置为挂起态的任务才可以使用 vTaskRexume()恢复。
xTaskResumeFromISR()
/*-------------------函数原型------------------*/
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume)
此函数是 vTaskResume()的中断版本,用于在中断服务函数中恢复一个任务
返回值:
pdTrue:恢复运行的任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),这意味着在退出中断服务函数以后必须进行一次上下文切换。
pdFALSE: 恢复运行的任务的任务优先级低于当前正在运行的任务(被中断打断的
任务),这意味着在退出中断服务函数的以后不需要进行上下文切换。
实验需求
通过两个按键来控制LED0的挂起与恢复
key.h
#ifndef _KEY_H_
#define _KEY_H_
#include "stm32f10x.h"
#include "delay.h"
//#define KEY0 GPIO_Pin_5
//#define KEY1 GPIO_Pin_6
//#define KEY2 GPIO_Pin_7
//#define KEY3 GPIO_Pin_8
//#define KEY4 GPIO_Pin_9
#define GPIO_PORT GPIOB
#define GPIO_PIN GPIO_Pin_4|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9
#define KEY0 GPIO_ReadInputDataBit(GPIO_PORT,GPIO_Pin_9) //读GPIO端口的输入,输入等于0返回1
#define KEY1 GPIO_ReadInputDataBit(GPIO_PORT,GPIO_Pin_8) //读GPIO端口的输入,输入等于0返回2
#define KEY2 GPIO_ReadInputDataBit(GPIO_PORT,GPIO_Pin_7) //读GPIO端口的输入,输入等于0返回3
#define KEY3 GPIO_ReadInputDataBit(GPIO_PORT,GPIO_Pin_6) //读GPIO端口的输入,输入等于0返回4
#define KEY4 GPIO_ReadInputDataBit(GPIO_PORT,GPIO_Pin_4) //读GPIO端口的输入,输入等于0返回4
#define KEY_ON 0 //按键按下为0
#define KEY_OFF -1 //按键没有按下为-1
#define KEY0_Value 1 //按键1的返回值
#define KEY1_Value 2 //按键1的返回值
#define KEY2_Value 3 //按键2的返回值
#define KEY3_Value 4 //按键3的返回值
#define KEY4_Value 5 //按键4的返回值
#define Error -2 //错误值返回
void KEY_GPIO_INIT(void);
unsigned char KEY_Scan(void);
#endif
key.c
void KEY_GPIO_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
//独立键盘扫描函数
unsigned char KEY_Scan(void)
{
// KEY_GPIO_INIT();
//keyvalue = 0;
if(KEY0==0||KEY1==0||KEY2==0||KEY3==0)
{
delay_ms(20);//去抖动
if(KEY0==0) //按键0按下
{
while(KEY0 == 0);
return KEY0_Value;
}
else if(KEY1==0) //按键1按下
{
while(KEY1 == 0);
return KEY1_Value;
}
else if(KEY2==0) //按键2按下
{
//delay_ms(10);
while(KEY2 == 0);
return KEY2_Value;
}
else if(KEY3==0) //按键3按下
{
//delay_ms(10);
while(KEY3 == 0);
return KEY3_Value;
}
else if(KEY4==0)
{
while(KEY4 == 0);
return KEY4_Value;
}
}
return 0;// 无按键按下
}
主函数
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define LED0_TASK_PRIO 4
//任务堆栈大小
#define LED0_STK_SIZE 50
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);
//任务优先级
#define LED1_TASK_PRIO 3
//任务堆栈大小
#define LED1_STK_SIZE 50
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);
//按键任务
#define KEY_TASK_PRIO 2
//任务堆栈大小
#define KEY_STK_SIZE 50
//任务句柄
TaskHandle_t KEYTask_Handler;
//任务函数
void key_task(void *pvParameters);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
KEY_GPIO_INIT(); //按键初始化
//创建开始任务
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(); //进入临界区
//创建LED0任务
xTaskCreate((TaskFunction_t )led0_task,
(const char* )"led0_task",
(uint16_t )LED0_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED0_TASK_PRIO,
(TaskHandle_t* )&LED0Task_Handler);
//创建LED1任务
xTaskCreate((TaskFunction_t )led1_task,
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
//创建按键任务
xTaskCreate((TaskFunction_t )key_task,
(const char* )"key_task",
(uint16_t )KEY_STK_SIZE,
(void* )NULL,
(UBaseType_t )KEY_TASK_PRIO,
(TaskHandle_t* )&KEYTask_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//LED0任务函数
void led0_task(void *pvParameters)
{
while(1)
{
LED0=~LED0;
vTaskDelay(500);
printf("led1 is running\r\n");
}
}
//LED1任务函数
void led1_task(void *pvParameters)
{
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
printf("led2 is running\r\n");
}
}
//按键任务函数
void key_task(void *pvParameters)
{
while(1)
{
//功能代码
//使用两个震动传感器 一个用于挂起 一个用于解挂
if(GPIO_ReadInputDataBit(GPIO_PORT,GPIO_Pin_9) == 0)
{
delay_ms(20); //消抖
while(GPIO_ReadInputDataBit(GPIO_PORT,GPIO_Pin_9) == 0); //等待按键抬起
vTaskDelay(100);
//挂起
vTaskSuspend(LED0Task_Handler);
printf("Task0 is Suspend\r\n");
}
if(GPIO_ReadInputDataBit(GPIO_PORT,GPIO_Pin_8) == 0)
{
delay_ms(20); //消抖
while(GPIO_ReadInputDataBit(GPIO_PORT,GPIO_Pin_8) == 0); //等待按键抬起
vTaskDelay(100);
//挂起
vTaskResume(LED0Task_Handler);
printf("Task0 is Resume\r\n");
}
}
}
实验结果