FreeRTOS之任务挂起和恢复

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实现。当在中断里恢复任务时,需要判断任务的返回值,根据返回值判断是否要进行任务切换。

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值