FreeRTOS:任务的创建和删除

一、函数xTaskCreate

此函数用来创建一个任务,任务需要RAM来保存与任务有关的状态信息(任务控制块),任务也需要一定的RAM 来作为任务堆栈。
如果使用函数xTaskCreate()来创建任务的话那么这些所需的RAM就会自动的从FreeRTOS的堆中分配,因此必须提供内存管理文件,默认我们使用heap_4.c这个内存管理文件,而且宏configSUPPORT_DYNAMIC_ALLOCATION必须为1。
如果使用函数xTaskCreateStatic()创建的话这些RAM就需要用户来提供了。新创建的任务默认就是就绪态的,如果当前没有比它更高优先级的任务运行那么此任务就会立即进入运行态开始运行,不管在任务调度器启动前还是启动后,都可以创建任务。此函数也是我们以后经常用到的,函数原型如下:

 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:任务名字,一般用于追踪和调试,任务名字长度不能超configMAX_TASK_NAME_LEN。
usStackDepth:任务堆栈大小,注意实际申请到的堆栈是usStackDepth的4倍,例如数值128,即128字。其中空闲任务的任务堆栈大小为 configMINIMAL_STACK_SIZE。
pvParameters:传递给任务函数的参数。
uxPriotiry:任务优先级,范围0~configMAX_PRIORITIES-1。若填写的数值超过configMAX_PRIORITIES-1,则静默地配置为 configMAX_PRIORITIES-1。有些版本增加了configASSERT( uxPriority<configMAX_PRIORITIES )语句,且使能configASSERT_DEFINED,则停留在该处。
pxCreatedTask:任务句柄,任务创建成功以后会返回此任务的任务句柄,这个句柄其实就是任务的任务堆栈。此参数就用来保存这个任 务句柄。其他API函数可能会使用到这个句柄。

返回值:
pdPASS:任务创建成功。
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:任务创建失败,因为堆内存不足!

二、函数xTaskCreateStatic

此函数和xTaskCreate()的功能相同,也是用来创建任务的,但是使用此函数创建的任务所需的 RAM需要用用户来提供。如果要使用此函数的话需要将configSUPPORT_STATIC_ALLOCATION定义为1。函数原型如下:

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:任务名字,一般用于追踪和调试,任务名字长度不能超configMAX_TASK_NAME_LEN。
usStackDepth:任务堆栈大小,由于本函数是静态方法创建任务,所以任务堆栈由用户给出,一般是个数组,此参数就是这个数组的大小。
pvParameters:传递给任务函数的参数。
uxPriotiry:任务优先级,范围 0~configMAX_PRIORITIES-1,数值越大,优先级就越高,在FreeRTOSConfig.h可以配置configMAX_PRIORITIES.若填写的数值超过configMAX_PRIORITIES-1,则静默地配置为configMAX_PRIORITIES-1。有些版本增加了
configASSERT( uxPriority < configMAX_PRIORITIES )语句,且使能configASSERT_DEFINED,则停留在该处。
puxStackBuffer:任务堆栈,一般为数组,数组类型要为StackType_t类型。
pxTaskBuffer:任务控制块。

返回值:
NULL;任务创建失败,puxStackBuffer 或 pxTaskBuffer为 NULL的时候会导致这个错误的发生。
其他值:任务创建成功,返回任务的任务句柄

三、函数xTaskCreateRestricted

此函数也是用来创建任务的,只不过此函数要求所使用的MCU有MPU(内存保护单元),用此函数创建的任务会受到MPU的保护。其他的功能和函数xTaskCreate()一样。

BaseType_t xTaskCreateRestricted( 
        const TaskParameters_t * const pxTaskDefinition,
        TaskHandle_t *pxCreatedTask );

参数:
pxTaskDefinition:指向一个结构体TaskParameters_t,这个结构体描述了任务的任务函数、堆栈大小、优先级等。此结构体在文件 task.h中有定义。
pxCreatedTask:任务句柄。

返回值:
pdPASS:任务创建成功。
其他值:任务创建失败,因为堆栈内存不足!

四、函数vTaskDelete

删除一个用函数xTaskCreate()或者xTaskCreateStatic()创建的任务,被删除了的任务不再存在,也就是说再也不 会进入运行态。任务被删除以后就不能再使用此任务的句柄!如果此任务是使用动态方法创建的,也就是使用函数 xTaskCreate()创建的,那么在此任务被删除以后此任务之前申请的堆栈和控制块内存会在空闲任务中被释放掉,因此当 调用函数vTaskDelete()删除任务以后必须给空闲任务一定的运行时间。
只有那些由内核分配给任务的内存才会在任务被删除以后自动的释放掉,用户分配给任务的内存需要用户自行释放 掉,比如某个任务中用户调用函数 pvPortMalloc()分配了500字节的内存,那么在此任务被删除以后用户也必须调用函数
vPortFree()将这500字节的内存释放掉,否则会导致内存泄露。此函数原型如下:

 vTaskDelete( TaskHandle_t xTaskToDelete )

五、任务创建和删除(动态)代码

5.1实验要求

设计4个任务:start_task、task1、task2、task3

start_task任务:用来创建其他三个任务
task1任务:实现LED0每500ms翻转一次
task2任务:实现LED1亮800ms,暗200ms
task3任务:判断按键KEY0是否按下,按下KEY0删除task1

5.2程序代码

#include "led.h"
#include "key.h"
#include "delay.h"
#include "sys.h"
#include "FreeRTOS.h"
#include "task.h"
 
/*START_TASK 任务配置
 *包括:任务句柄,任务优先级,堆栈大小,创建任务
 */
//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_TASK_STACK_SIZE   128  //单位是字,128x4才是字节
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
 
/*TASK1 任务配置
 *包括:任务句柄,任务优先级,堆栈大小,创建任务
 */
//任务优先级
#define TASK1_PRIO		2
//任务堆栈大小	
#define TASK1_SIZE 		50  
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);
 
/*TASK2 任务配置
 *包括:任务句柄,任务优先级,堆栈大小,创建任务
 */
//任务优先级
#define TASK2_PRIO		3
//任务堆栈大小	
#define TASK2_SIZE 		50  
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);
 
/*TASK3 任务配置
 *包括:任务句柄,任务优先级,堆栈大小,创建任务
 */
 //任务优先级
#define TASK3_PRIO		4
//任务堆栈大小	
#define TASK3_SIZE 		50  
//任务句柄
TaskHandle_t Task3_Handler;
//任务函数
void task3(void *pvParameters);
 
int main(void)
{
    
    
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	KEY_Init();               //按键初始化
	//创建开始任务
	  xTaskCreate(	(TaskFunction_t ) ,
									(const char *  	) "start_task",
									(uint16_t				) START_TASK_STACK_SIZE,
									(void *        	) NULL,
									(UBaseType_t   	) START_TASK_PRIO,
									(TaskHandle_t *	) &StartTask_Handler );							
    vTaskStartScheduler();          //开启任务调度
}
 
//开始任务任务函数
void start_task(void *pvParameters)
{
    
    
    taskENTER_CRITICAL();           //进入临界区
    //创建taask1任务
    xTaskCreate((TaskFunction_t )task1,     	
                (const char*    )"task1",   	
                (uint16_t       )TASK1_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TASK1_PRIO,	
                (TaskHandle_t*  )&Task1_Handler);   
    //创建task2任务
    xTaskCreate((TaskFunction_t )task2,     
                (const char*    )"task2",   
                (uint16_t       )TASK2_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK2_PRIO,
                (TaskHandle_t*  )&Task2_Handler);        
			//创建task3任务
    xTaskCreate((TaskFunction_t )task3,     
                (const char*    )"task3",   
                (uint16_t       )TASK3_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )TASK3_PRIO,
                (TaskHandle_t*  )&Task3_Handler);
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}
 
//task1任务函数:实现LED0每500ms翻转一次
void task1(void *pvParameters)
{
    
    
    while(1)
    {
    
    
			  printf("Task1\r\n");
        LED0=~LED0;
        vTaskDelay(500);
    }
}   
 
//task2任务函数:实现LED1每800ms翻转一次
void task2(void *pvParameters)
{
    
    
    while(1)
    {
    
    
			  printf("Task2\r\n");
				LED1=0;
        vTaskDelay(200);
        LED1=1;
        vTaskDelay(800);		
    }
}
 
//task3任务函数:判断按键KEY0,按下KEY0删除task1
void task3(void *pvParameters)
{
    
    
	uint8_t key = 0;
	while(1)
	{
    
    
		printf("Task3\r\n");
		key = KEY_Scan(0);
		if(key == KEY0_PRES)
		{
    
    
			printf("删除Task1\r\n");
			vTaskDelete(Task1_Handler);
		}
		 vTaskDelay(10);
	}
}

六、任务创建和删除(静态)代码

6.1实验要求

设计4个任务:start_task、task1、task2、task3

start_task任务:用来创建其他三个任务
task1任务:实现LED0每500ms翻转一次
task2任务:实现LED1亮800ms,暗200ms
task3任务:判断按键KEY0是否按下,按下KEY0删除task1

6.2程序代码

#include "led.h"
#include "key.h"
#include "delay.h"
#include "sys.h"
#include "FreeRTOS.h"
#include "task.h"
 
/*START_TASK 任务配置
 *包括:任务句柄,任务优先级,堆栈大小,创建任务
 */
//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_TASK_STACK_SIZE   128  //单位是字,128x4才是字节
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//自定义堆栈大小
StackType_t  start_task_stack[START_TASK_STACK_SIZE];
//开始任务的任务控制块
StaticTask_t start_task_tcb;
 
/*TASK1 任务配置
 *包括:任务句柄,任务优先级,堆栈大小,创建任务
 */
//任务优先级
#define TASK1_PRIO		2
//任务堆栈大小	
#define TASK1_SIZE 		50  
//任务句柄
TaskHandle_t Task1_Handler;
//任务函数
void task1(void *pvParameters);
//自定义堆栈大小
StackType_t  task1_stack[TASK1_SIZE];
//开始任务的任务控制块
StaticTask_t task1_tcb;
 
 
/*TASK2 任务配置
 *包括:任务句柄,任务优先级,堆栈大小,创建任务
 */
//任务优先级
#define TASK2_PRIO		3
//任务堆栈大小	
#define TASK2_SIZE 		50  
//任务句柄
TaskHandle_t Task2_Handler;
//任务函数
void task2(void *pvParameters);
//自定义堆栈大小
StackType_t  task2_stack[TASK1_SIZE];
//开始任务的任务控制块
StaticTask_t task2_tcb;
 
 
/*TASK3 任务配置
 *包括:任务句柄,任务优先级,堆栈大小,创建任务
 */
 //任务优先级
#define TASK3_PRIO		4
//任务堆栈大小	
#define TASK3_SIZE 		50  
//任务句柄
TaskHandle_t Task3_Handler;
//任务函数
void task3(void *pvParameters);
//自定义堆栈大小
StackType_t  task3_stack[TASK1_SIZE];
//开始任务的任务控制块
StaticTask_t task3_tcb;
 
//空闲任务配置
StaticTask_t idle_task_tcb;
StackType_t idel_task_stack[configMINIMAL_STACK_SIZE];
 /*空闲任务内存分配*/
void vApplicationGetIdleTaskMemory ( StaticTask_t **ppxIdleTaskTCBBuffer,
									 StackType_t **ppxIdleTaskStackBuffer, 
									 uint32_t *pulIdleTaskStackSize )
{
    
    
	* ppxIdleTaskTCBBuffer = &idle_task_tcb;
	* ppxIdleTaskStackBuffer = idel_task_stack;
	* pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
 
//软件定时器配置
StaticTask_t time_task_tcb;
StackType_t time_task_stack[configTIMER_TASK_STACK_DEPTH];
 /*软件定时器内存分配*/
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
									 StackType_t **ppxTimerTaskStackBuffer,
                                     uint32_t *pulTimerTaskStackSize)
{
    
    
	 * ppxTimerTaskTCBBuffer = &time_task_tcb;
	 * ppxTimerTaskStackBuffer = time_task_stack;
     * pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}  
int main(void)
{
    
    
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	KEY_Init();               //按键初始化
	//创建开始任务
  StartTask_Handler = xTaskCreateStatic(	(TaskFunction_t  )   start_task,
											(char *     	 )   "start_task",
			                				(uint32_t		 )   START_TASK_STACK_SIZE,
											(void *			 )   NULL,
										 	(UBaseType_t	 )   START_TASK_PRIO,																					 
                                            (StackType_t * )   start_task_stack,
											(StaticTask_t *)   &start_task_tcb);										
    vTaskStartScheduler();          //开启任务调度
}
 
//开始任务任务函数
void start_task(void *pvParameters)
{
    
    
    taskENTER_CRITICAL();           //进入临界区
    //创建task1任务
   Task1_Handler = xTaskCreateStatic(	(TaskFunction_t)   task1,
										(char * 			 )   "task1",
										(uint32_t			 )   TASK1_SIZE,
										(void *				 )   NULL,
										(UBaseType_t	 )   TASK1_PRIO,
										(StackType_t * )   task1_stack,
										(StaticTask_t *)   &task1_tcb);										 
    //创建task2任务
  Task2_Handler = xTaskCreateStatic(	(TaskFunction_t)   task2,
										(char * 			 )   "task2",
								    	(uint32_t			 )   TASK2_SIZE,
										(void *				 )   NULL,
										(UBaseType_t	 )   TASK2_PRIO,
										(StackType_t * )   task2_stack,
										(StaticTask_t *)   &task2_tcb);		     
  //创建task3任务
  Task3_Handler = xTaskCreateStatic(	(TaskFunction_t)   task3,
										(char * 			 )   "task3",
										(uint32_t			 )   TASK3_SIZE,
										(void *				 )   NULL,
										(UBaseType_t	 )   TASK3_PRIO,
										(StackType_t * )   task3_stack,
										(StaticTask_t *)   &task3_tcb);
    vTaskDelete(NULL); //删除开始任务  也可以写成vTaskDelete(StartTask_Handler);
    taskEXIT_CRITICAL();            //退出临界区
}
 
//task1任务函数:实现LED0每500ms翻转一次
void task1(void *pvParameters)
{
    
    
    while(1)
    {
    
    
        LED0=!LED0;
        vTaskDelay(500);
    }
}   
 
//task2任务函数:实现LED1每800ms翻转一次
void task2(void *pvParameters)
{
    
    
    while(1)
    {
    
    
				LED1=0;
        vTaskDelay(200);
        LED1=1;
        vTaskDelay(800);		
    }
}
 
//task3任务函数:判断按键KEY0,按下KEY0删除task1
void task3(void *pvParameters)
{
    
    
	uint8_t key = 0;
	while(1)
	{
    
    
		key = KEY_Scan(0);
		if(key == KEY0_PRES)
		{
    
    
			vTaskDelete(Task1_Handler);
		}
		 vTaskDelay(10);
	}
}

七、动态创建任务和静态创建任务的区别

(1)动态创建任务:任务的任务控制块以及任务的栈空间所需的内存均由FreeRTOS从FreeRTOS管理的堆中分配;

(2)静态创建任务:任务的任务控制块以及任务的栈空间所需的内存需要用户分配提供。

静态创建任务需要注意:
(1)代码中将宏#define configSUPPORT_STATIC_ALLOCATION配置为1;

#define configSUPPORT_STATIC_ALLOCATION         1            //支持静态内存申请

(2)定义配置空闲任务,软件定时器,实现两个接口函数:vApplicationGetIdleTaskMemory、vApplicationGetTimerTaskMemory;

//空闲任务配置
StaticTask_t idle_task_tcb;
StackType_t idel_task_stack[configMINIMAL_STACK_SIZE];
 /*空闲任务内存分配*/
void vApplicationGetIdleTaskMemory ( StaticTask_t **ppxIdleTaskTCBBuffer,
																		 StackType_t **ppxIdleTaskStackBuffer, 
																		 uint32_t *pulIdleTaskStackSize )
{
    
    
	* ppxIdleTaskTCBBuffer = &idle_task_tcb;
	* ppxIdleTaskStackBuffer = idel_task_stack;
	* pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
 
//软件定时器配置
StaticTask_t time_task_tcb;
StackType_t time_task_stack[configTIMER_TASK_STACK_DEPTH];
 /*软件定时器内存分配*/
void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer,
																		 StackType_t **ppxTimerTaskStackBuffer,
                                     uint32_t *pulTimerTaskStackSize)
{
    
    
	 * ppxTimerTaskTCBBuffer = &time_task_tcb;
	 * ppxTimerTaskStackBuffer = time_task_stack;
   * pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
} 

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_27928443/article/details/130494879