freertos任务的创建、删除、挂起、恢复

本文详细介绍了FreeRTOS操作系统中任务的动态和静态创建,包括xTaskCreate和xTaskCreateStatic函数的使用,以及任务的删除函数vTaskDelete。同时,讨论了任务的挂起和恢复,包括vTaskSuspend、vTaskResume和xTaskResumeFromISR的功能和应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、任务创建

1.动态创建任务xTaskCreate( )

函数原型:

BaseType_t xTaskCreate(
        TaskFunction_t pxTaskCode ,
        const char * const pcName ,
        const uint16_t usStackDepth ,
        void * const pvParameters ,
        UBaseType_t uxPriority ,
        TaskHandle_t * const pxCreatedTask );
参数:
pxTaskCode : 任务函数。
pcName : 任务名字,一般用于追踪和调试。
usStackDepth : 任务堆栈大小,实际申请到的堆栈是 usStackDepth 4 倍。
pvParameters: 传递给任务函数的参数。
uxPriotiry: 任务优先级,范围 0~ configMAX_PRIORITIES-1
pxCreatedTask: 任务控制块,又叫任务句柄,包含创建任务的所有信息。
返回值: pdPASS: 任务创建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY : 任务创建失败,因为堆内
存不足!
完整动态创建一个任务代码:
//任务优先级
#define LED0_TASK_PRIO		3
//任务堆栈大小	
#define LED0_STK_SIZE 		50  
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);

//创建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); //任务句柄  

void led0_task(void *pvParameters)
{
	u8 task0_num = 0;
	while(1)
	{
		task0_num++;
		LED0=!LED0;
		printf("task_led0已经执行:  %d次\r\n",task0_num);
		vTaskDelay(1000);
	}

} 

2.静态创建任务xTaskCreateStatic()

函数原型:
TaskHandle_t xTaskCreateStatic(
        TaskFunction_t pxTaskCode,
        const char * const pcName,
        const uint32_t ulStackDepth,
        void * const pvParameters,
        UBaseType_t uxPriority,
        StackType_t * const puxStackBuffer,
        StaticTask_t * const pxTaskBuffer )
参数:
pxTaskCode : 任务函数。
pcName : 任务名字,一般用于追踪和调试
usStackDepth : 任务堆栈大小,由于本函数是静态方法创建任务,所以任务堆
栈由用户给出,一般是个数组,此参数就是这个数组的大小。
pvParameters: 传递给任务函数的参数。
uxPriotiry: 任务优先级,范围 0~ configMAX_PRIORITIES-1
puxStackBuffer: 任务堆栈,一般为数组,数组类型要为 StackType_t 类型。
pxTaskBuffer: 任务控制块 .
返回值:
NULL : 任务创建失败, puxStackBuffer pxTaskBuffer NULL 的时候会导
致这个错误的发生
其他值 : 任务创建成功, 返回任务的任务句柄
注:一般不用静态创建

二、任务删除vTaskDelete

vTaskDelete() :删除一个用函数 xTaskCreate() 或者 xTaskCreateStatic() 创建的任务,被删除了的任务不再存在,也就是说再也不会进入运行态。任务 被删除以后就不能再使用此任务的句柄!
示例:任务0删除任务1:
void led0_task(void *pvParameters)
{
	vTaskDelay(10000);
	if(LED1Task_Handler != NULL) //判断led1任务是否存在
	{
		vTaskDelete(LED1Task_Handler);//删除led1任务
		LED1Task_Handler=NULL; //led1任务句柄清零
		printf("led0任务删除了led1任务\r\n");
	}
	while(1)
	{
		LED0=!LED0;
		vTaskDelay(1000); 
	}

}   


//LED1任务函数
void led1_task(void *pvParameters)//创建10秒后被led0任务删除了
{
    while(1)
    {
			printf("this is led1_task......\r\n");
			LED1 = 1;
			vTaskDelay(500);
			LED1 = 0;
			vTaskDelay(500);
    }
}

三、任务的挂起、恢复

1.任务的挂起

当某个任务要停止运行一段时间的话就将这个任务挂起,当要重新运行这个任务的话就恢复这个任务的运行。
函数: vTaskSuspend()
参数:要挂起任务的句柄,如果为NULL的话表示挂起任务自己
vTaskSuspend(LED0Task_Handler);
此函数用于将某个任务设置为挂起态,进入挂起态的 任务永远都不会进入运行态。退出挂起态的唯一方法就是调用任务恢复 函数 vTaskResume()或 xTaskResumeFromISR()

2.任务中恢复

函数:vTaskResume()

参数:要恢复的任务的任务句柄

3.任务从中断中恢复

函数:xTaskResumeFromISR()

参数:要恢复的任务的任务句柄

返回值:

pdTRUE:恢复的任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),这意味着在退出中断服务函数以后要进行一次上下文切换

pdFALSE:恢复的任务的任务优先级低于正在运行的任务(被中断打断的任务),这意味着在退出中断服务函数以后不需要进行一次上下文切换

测试代码:

按键扫描进行挂起任务,另外一个按键用中断的方式实现中断中恢复任务:

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "timer.h"
#include "key.h"



//任务优先级
#define LED0_TASK_PRIO		1
//任务堆栈大小	
#define LED0_STK_SIZE 		50  
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);

//任务优先级
#define LED1_TASK_PRIO		2
//任务堆栈大小	
#define LED1_STK_SIZE 		50  
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);

//任务优先级
#define KEY_TASK_PRIO		4
//任务堆栈大小	
#define KEY_STK_SIZE 		50  
//任务句柄
TaskHandle_t KEYTask_Handler;
//任务函数
void key_task(void *pvParameters);

uint16_t sum1=0;
uint16_t sum2=0;
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4(freertos)	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	TIM3_Init(9999,7199);
	KEY_Init();
	//创建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);
								
		//创建KEY任务
    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);
		
    vTaskStartScheduler();          //开启任务调度
		/*
			调度器并非自动运行的,需要人为启动它。 API函
			数vTaskStartScheduler()用于启动调度器,它会创建一个空闲任务、初始化一些
			静态变量,最主要的,它会初始化系统节拍定时器并设置好相应的中断,然后启
			动第一个任务
		*/
		
}

u8 KEY_scan(void)
{
	static u8 key_up = 1;
	if(key_up && ( KEY5==0 || KEY6==0))
	{
		delay_xms(20);
		key_up = 0;
		if(KEY5==0) return KEY5_PRESS;
		else if(KEY6==0) return KEY6_PRESS;
	}
	else if (KEY5==1&&KEY6==1) 
	{
		key_up=1;
		return 0;
	}
}

void key_task(void *pvParameters)
{
	u8 key;
	while(1)
	{
		key=KEY_scan();
		switch(key)
		{
			case KEY5_PRESS:
				printf("挂起任务led0\r\n");
				vTaskSuspend(LED0Task_Handler);
				break;
		}
		vTaskDelay(100);
	}
}

void led0_task(void *pvParameters)
{
	u8 task0_num = 0;
	while(1)
	{
		task0_num++;
		LED0=!LED0;
		printf("task_led0已经执行:  %d次\r\n",task0_num);
		vTaskDelay(1000);
	}

}   

//LED1任务函数
void led1_task(void *pvParameters)//创建5秒后被led0任务删除了
{
		u8 task1_num = 0;
    while(1)
    {
			task1_num++;
			LED1=!LED1;
			delay_xms(2000);
			printf("task_led1已经执行:  %d次\r\n",task1_num);
			delay_xms(1000);
			vTaskDelay(30);
    }
}

key.c

#include "stm32f10x.h"
#include "key.h"
#include "delay.h"
#include "usart.h"
#include "stdio.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
extern TaskHandle_t LED0Task_Handler;
void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; 
	EXTI_InitTypeDef EXTI_InitStructure; 	
	NVIC_InitTypeDef NVIC_InitStructure;	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource4);

	
	
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断请求模式
	EXTI_InitStructure.EXTI_Line = EXTI_Line4; //外部中断线
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //设置输入线路下降沿为中断请求
	EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
	EXTI_Init(&EXTI_InitStructure);//初始化
	
	NVIC_InitStructure.NVIC_IRQChannel =EXTI4_IRQn; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =6;//抢占优先级,>=5
	NVIC_Init(&NVIC_InitStructure);
	
	
}

void EXTI4_IRQHandler(void)
{
	BaseType_t YieldRequired;
	if(EXTI_GetITStatus(EXTI_Line4)!=RESET)
	{
	delay_xms(100);
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_4)==0)
	{	
		YieldRequired=xTaskResumeFromISR(LED0Task_Handler);//恢复任务,返回值为pdTRUE或者pdFALSE
		printf("恢复任务led0\r\n");
		if(YieldRequired==pdTRUE)//如果恢复的任务优先级高于或等于正在运行的任务,则马上强制切换任务
		{
			portYIELD_FROM_ISR(YieldRequired);
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line4);//清除EXTI线路挂起位
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

香菜是个好东西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值