1.本文介绍FreeRTOS的任务挂起和恢复函数。任务删除后将不再存在,不能恢复,而任务挂起是暂停任务,可以通过调用函数进行恢复。FreeRTOS任务挂起和恢复的主要步骤如下:
(1)将相关的宏定义设置为1:INCLUDE_vTaskSuspend、INCLUDE_xTaskResumeFromISR
(2)调用函数任务挂起函数vTaskSuspend(),调用任务恢复函数vTaskResume()和xTaskResumeFromISR()。函数xTaskResumeFromISR()是从中断服务函数里恢复任务。
2.宏定义INCLUDE_vTaskSuspend和INCLUDE_xTaskResumeFromISR的设置:
3.调用任务挂起函数vTaskSuspend():
vTaskSuspend()没有返回值,入口参数为需要被挂起任务的句柄。
4.调用任务恢复函数vTaskResume()和xTaskResumeFromISR():
(1)vTaskResume()没有返回值,入口参数为需要被恢复的任务句柄。
(2)xTaskResumeFromISR()是从中断里恢复被挂起的任务,入口参数为需要被恢复的任务的句柄。xTaskResumeFromISR()的返回值为pdTRUE和pdFALSE。
当返回pdTRUE时,表明被恢复的任务的优先级要等于或高于当前正在执行的任务(被中断打断的任务),因此需要调用函数portYIELD_FROM_ISR()进行一次任务切换。
当返回pdFALSE时,表明被恢复的任务的优先级要小于当前正在执行的任务(被中断打断的任务),,不需要进行任务切换。
此外,使用xTaskResumeFromISR()需要注意,系统中断优先级不能高于FreeRTOS能管理的中断优先级。通常FreeRTOS可以管理的任务优先级为5-15,因此,本文将按键的中断优先级设置为5。为了方便FreeRTOS管理,建议将子优先级设置为0。
5.代码:本文只展示main函数和中断服务函数部分的代码,若需要完整的代码,可以将本文和前面的动态创建任务部分的代码进行结合。
(1)exit代码:
#include "exti.h"
#include "key.h"
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
extern TaskHandle_t led0_handler;
void EXTIx_Init(void)
{
/*ÍⲿÖжϵÄÅäÖ÷½·¨£º
1.½«IO¿ÚÓ³Éäµ½¶ÔÓ¦ÍⲿÖжÏÏßÉÏ
2.ÅäÖÃÍⲿÖжÏ
3.ÖØдÖжϷþÎñº¯Êý£¬¼´Öжϻص÷º¯Êý*/
//¶¨ÒåÍⲿÖжϺÍÖжϵĽṹÌ壺
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//ʹÄÜʱÖÓ£º
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//ÍⲿÖжÏÐèÒª¸´ÓÃʱÖÓ
KEY_Init(); //³õʼ»¯°´¼ü
//GPIOA.0µÄÖжÏÏߺÍÖжϳõʼ»¯ÅäÖãº
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //GPIOÓëÖжÏÏß½øÐÐÓ³Éä
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStructure);
EXTI_Init(&EXTI_InitStructure);
//ÖжϹÜÀíÅäÖãº
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStructure);
}
//ÖØдÖжϷþÎñº¯Êý.
void EXTI0_IRQHandler(void)
{
//¾²Ì¬±äÁ¿Ö»»áÔÚµÚÒ»´ÎÔËÐÐʱ±»³õʼ»¯¡£ËùÒÔ£¬¿ÉÒÔÀí½âΪÕâÌõÓï¾äÖ»Ö´ÐÐÒ»´Î
//static u8 flag1 = 1;
delay_us(1000); //Ïû¶¶
if(KEY_2 == 1)
{
BaseType_t xYieldRequired;
xYieldRequired = xTaskResumeFromISR(led0_handler);
if(xYieldRequired == pdTRUE)
{
portYIELD_FROM_ISR(xYieldRequired);
}
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
#ifndef __EXTI_H
#define __EXTI_H
#include "stm32f10x.h"
void EXTIx_Init(void);
#endif
(2)main代码:
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "exti.h"
#include "sys.h"
//¶¨Òåstart_taskµÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define START_TASK_PRIO 1
#define START_TASK_STACK_SIZE 64
TaskHandle_t start_handler;
void start_task(void);
//¶¨ÒåÈÎÎñ1µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define LED0_TASK_PRIO 2
#define LED0_TASK_STACK_SIZE 64
TaskHandle_t led0_handler;
void led0(void);
//¶¨ÒåÈÎÎñ2µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define LED1_TASK_PRIO 3
#define LED1_TASK_STACK_SIZE 64
TaskHandle_t led1_handler;
void led1(void);
//¶¨ÒåÈÎÎñ2µÄÅäÖã¬ÈÎÎñ¾ä±ú£¬ÈÎÎñÓÅÏȼ¶£¬¶ÑÕ»´óС£¬ÈÎÎñÉùÃ÷£º
#define KEY_TASK_PRIO 4
#define KEY_TASK_STACK_SIZE 64
TaskHandle_t key_handler;
void key_task(void);
int flag = 0;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);// ÉèÖÃÖжÏÓÅÏȼ¶·Ö×é4£¬¼´×ÓÓÅÏȼ¶Îª0
LED_Init();
KEY_Init();
delay_init();
EXTIx_Init();
xTaskCreate((TaskFunction_t) start_task, //ÈÎÎñº¯Êý
(const char *)"start_task", //ÈÎÎñÃû³Æ
(uint16_t)START_TASK_STACK_SIZE, //ÈÎÎñ¶ÑÕ»´óС
(void *)NULL, //´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý
(UBaseType_t)START_TASK_PRIO, //ÈÎÎñÓÅÏȼ¶
(TaskHandle_t *)&start_handler); //ÈÎÎñ¾ä±ú
vTaskStartScheduler(); //¿ªÊ¼ÈÎÎñµ÷¶È
}
/*´´½¨¿ªÊ¼ÈÎÎñ£º*/
void start_task(void)
{
// taskENTER_CRITICAL();
/*´´½¨ÈÎÎñ*/
if(flag == 0)
{
xTaskCreate((TaskFunction_t) led0, //ÈÎÎñº¯Êý
(const char *)"led0_task", //ÈÎÎñÃû³Æ
(uint16_t)LED0_TASK_STACK_SIZE, //ÈÎÎñ¶ÑÕ»´óС
(void *)NULL, //´«µÝ¸øÈÎÎñº¯ÊýµÄ²ÎÊý
(UBaseType_t)LED0_TASK_PRIO, //ÈÎÎñÓÅÏȼ¶
(TaskHandle_t *)&led0_handler); //ÈÎÎñ¾ä±ú
xTaskCreate((TaskFunction_t) led1,
(const char *)"led1_task",
(uint16_t)LED1_TASK_STACK_SIZE,
(void *)NULL,
(UBaseType_t)LED1_TASK_PRIO,
(TaskHandle_t *)&led1_handler);
xTaskCreate((TaskFunction_t) key_task,
(const char *)"key_task",
(uint16_t)KEY_TASK_STACK_SIZE,
(void *)NULL,
(UBaseType_t)KEY_TASK_PRIO,
(TaskHandle_t *)&key_handler);
flag = 1;
}
vTaskDelay(500);
vTaskDelete(NULL); //ɾ³ýµ±Ç°ÈÎÎñ
// taskEXIT_CRITICAL();
}
void led0(void)
{
while(1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_8); //´ò¿ªLED
vTaskDelay(500);
//delay_ms(500);
GPIO_SetBits(GPIOA,GPIO_Pin_8); //´ò¿ªLED
vTaskDelay(500);
}
}
void led1(void)
{
while(1)
{
GPIO_ResetBits(GPIOD,GPIO_Pin_2); //´ò¿ªLED
vTaskDelay(500);
//delay_ms(500);
GPIO_SetBits(GPIOD,GPIO_Pin_2); //´ò¿ªLED
vTaskDelay(500);
}
}
/*´´½¨°´¼üÈÎÎñ£º*/
void key_task(void)
{
//uint8_t key = 0;
while(1)
{
//printf("task3ÕýÔÚÔËÐУ¡£¡£¡\r\n");
//key = KEY_Scan(0);
if(KEY_0 == 0) //°´¼ü0±»°´ÏÂʱ£¬¹ÒÆðled0ÈÎÎñ
{
vTaskSuspend(led0_handler);
}
else if(KEY_1 == 0) //°´¼ü1±»°´ÏÂʱ£¬»Ö¸´led0ÈÎÎñ
{
vTaskResume(led0_handler);
}
vTaskDelay(10);
}
}
6.运行结果:
当按下key0时,led0任务被挂起。当按下key1和key2时,led0任务被恢复。
7.总结:
本文中介绍了FreeRTOS的任务挂起和恢复函数,主要是通过调用函数API实现。当在中断里恢复任务时,需要判断任务的返回值,根据返回值判断是否要进行任务切换。