FreeRTOS - 任务的创建与删除

学习视频是正点原子FreeRTOS,板子使用的是正点原子STM32f103ZET6精英开发板。

声明: 

 任务的创建和删除本质就是调用FreeRTOS的API函数

 动态和静态方式创建任务区别:动态任务的任务控制块以及任务的栈空间所需的内存FreeRTOS 管理 的堆中分配。静态任务的任务控制块以及任务的栈空间所需的内存由 用户 分配提供。 

 动态创建任务

动态创建任务函数 

BaseType_t xTaskCreate
( 
       TaskFunction_t               pxTaskCode,	   //指向任务函数的指针			 
       const char * const       	pcName, 	//任务名字,最大长度 configMAX_TASK_NAME_LEN 
	   const configSTACK_DEPTH_TYPE usStackDepth,  // 任务堆栈大小,注意字为单位 
	   void * const 	            pvParameters,  //传递给任务函数的参数
	   UBaseType_t              	uxPriority,	//任务优先级,范围:0 ~configMAX_PRIORITIES-1 
	   TaskHandle_t * const         pxCreatedTask  //任务句柄,就是任务的任务控制块 
)
返回:

如果任务创建成功,则返回 pdPASS。 否则 返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY

参数说明 

参数说明
pvTaskCode  指向任务入口函数的指针。
pcName  

任务的描述性名称。主要是为了用于获取任务句柄。

任务名称的最大长度由 FreeRTOSConfig.h 中的 configMAX_TASK_NAME_LEN 定义。

uxStackDepth  

要分配用于任务堆栈的堆栈。例如,如果堆栈的宽度为 16 位,uxStackDepth 为 100,则将分配 200 字节用作该任务的堆栈。 再举一例,如果堆栈的宽度为 32 位,uxStackDepth 为 400,则将分配 1600 字节用作该任务的堆栈。

堆栈深度与堆栈宽度的乘积不得超过 size_t 类型变量所能包含的最大值。

pvParameters  作为参数传递给创建的任务的一个值。如果 pvParameters 设置为变量的地址, 则在执行创建的任务时该变量必须仍然存在——因此 传递堆栈变量的地址是无效的。
uxPriority  

创建任务执行的优先级 。在 uxPriority 中设置 portPRIVILEGE_BIT 位。

最大是( configMAX_priority - 1)。

pxCreatedTask  用于将句柄传递至由 xTaskCreate() 函数创建的任务 。 pxCreatedTask 是可选的,可设置为 NULL。

实现动态创建任务流程

  1. 将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1 
  2. 定义函数入口参数
  3. 编写任务函数

TCB任务控制块 

        任务TCB(任务控制块),这是一个关键点。它用于存储任务的状态信息,包括任务运行时的环境。任务TCB是一个相对比较大的数据结构。每个任务都有属于自己的任务控制块,类似身份证

typedef struct tskTaskControlBlock
{
    volatile StackType_t    *pxTopOfStack;   
    //当前堆栈的栈顶,必须位于结构体的第一项
    ListItem_t              xStateListItem;        
    //任务的状态列表项,以引用的方式表示任务的状态
    ListItem_t              xEventListItem;      
    //事件列表项,用于将任务以引用的方式挂接到事件列表
    UBaseType_t             uxPriority;                          
    //保存任务优先级,0表示最低优先级
    StackType_t             *pxStack;                            
    //指向堆栈的起始位置
    char                    pcTaskName[ configMAX_TASK_NAME_LEN ];
    //任务名字
    ...
    省略很多条件编译的成员
 
} tskTCB;
 
typedef tskTCB TCB_t;

官方动态创建任务说明书

实践代码

/*在freertosfig.h中*/
#define configSUPPORT_STATIC_ALLOCATION      1         /* 1: 支持静态申请内存, 默认: 0 */
#define configSUPPORT_DYNAMIC_ALLOCATION     1         /* 1: 支持动态申请内存, 默认: 1 */
/*********************************/

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"

#include "FreeRTOS.h"
#include "task.h"

#define START_TASK_PRIO   1            //任务优先级为 1
#define START_TASK_STACK_SIZE  128     //开始任务堆栈定义128 字
TaskHandle_t start_task_handler;       //定义任务句柄
void start_task(void * pvParameters);  //前面声明

#define TASK1_PRIO        2            //任务优先级为 2
#define TASK1_STACK_SIZE  128     
TaskHandle_t task1_handler;
void task1(void * pvParameters);

#define TASK2_PRIO        3            //任务优先级为 3
#define TASK2_STACK_SIZE  128         
TaskHandle_t task2_handler;
void task2(void * pvParameters);

#define TASK3_PRIO        4             //任务优先级为 4
#define TASK3_STACK_SIZE  128       
TaskHandle_t task3_handler;
void task3(void * pvParameters);


void freertos_demo(void)
{
    xTaskCreate( (TaskFunction_t  )          start_task,
                  (char *         )          "start_task", 
    			  (uint16_t       )          START_TASK_STACK_SIZE,
                  (void *         )          NULL,
                  (unsigned long  )          START_TASK_PRIO,
                  (TaskHandle_t * )          &start_task_handler );
    	
    vTaskStartScheduler();   //开启调度器
}

void start_task(void * pvParameters)
{
	taskENTER_CRITICAL();   //进入临界区
    xTaskCreate( (TaskFunction_t  )          task1,
                  (const char *   )          "task1", 
    			  (configSTACK_DEPTH_TYPE )  TASK1_STACK_SIZE,
                  (void *         )           NULL,
                  (UBaseType_t    )           TASK1_PRIO,
                  (TaskHandle_t * )           &task1_handler );
				  
	xTaskCreate( (TaskFunction_t  )          task2,
                  (const char *   )          "task2", 
    			  (configSTACK_DEPTH_TYPE )  TASK2_STACK_SIZE,
                  (void *         )           NULL,
                  (UBaseType_t    )           TASK2_PRIO,
                  (TaskHandle_t * )           &task2_handler );
				  
	xTaskCreate( (TaskFunction_t  )          task3,
                  (const char *   )          "task3", 
    			  (configSTACK_DEPTH_TYPE )  TASK3_STACK_SIZE,
                  (void *         )           NULL,
                  (UBaseType_t    )           TASK3_PRIO,
                  (TaskHandle_t * )           &task3_handler );
    vTaskDelete(NULL);                    //传入NULL删除自身
	taskEXIT_CRITICAL();                  //退出临界区
}
	
//LED0闪烁500ms
void task1(void * pvParameters)
{
	while(1)
	{
		printf("task1正在运行!!!\r\n");
		LED0_TOGGLE();
		vTaskDelay(500);
	}
	
}

//LED1闪烁500ms
void task2(void * pvParameters)
{
	
	while(1)
	{
		printf("task2正在运行!!!\r\n");
		LED1_TOGGLE();
		vTaskDelay(500);
	}
	
}

//按下KEY0关闭LED0
void task3(void * pvParameters)
{
	uint8_t key = 0;
	while(1)
	{
		printf("task3正在运行!!!\r\n");
		key = key_scan(0);
		if(key == KEY0_PRES)
		{
			vTaskDelete(task1_handler);
			
		}
		vTaskDelay(10);
	}
}

特殊说明

虽然xTaskCreate()看上去很像函数,但其实是一个宏,真正被调用的函数xTaskGenericCreate(),xTaskCreate()宏定义如下所示:

#define xTaskCreate( pvTaskCode,
                     pcName, 
                     usStackDepth,
                     pvParameters, 
                     uxPriority, 
                     pxCreatedTask )   
        xTaskGenericCreate( ( pvTaskCode ),
                            ( pcName ),
                            ( usStackDepth ), 
                            ( pvParameters ), 
                            ( uxPriority ), 
                            ( pxCreatedTask), 
                            ( NULL ), 
                            ( NULL ), 
                            ( NULL ) )

可以看到xTaskCreate比xTaskGenericCreate少了三个参数,在宏定义中,这三个参数被设置为NULL。这三个参数用于使用静态变量的方法分配堆栈、任务TCB空间以及设置MPU相关的参数。一般情况下,这三个参数是不使用的,所以任务创建宏xTaskCreate定义的时候,将这三个参数对用户隐藏了。接下来的章节中,为了方便,我们还是称xTaskCreate()为函数,虽然它是一个宏定义。

官方动态创建任务说明书

 静态创建任务

静态创建任务函数

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		    // 任务控制块指针,由用户分配
); 	
返回

如果 puxStackBuffer  pxTaskBuffer 均不为 NULL,则创建任务,并返回任务的句柄。          如果 puxStackBuffer  或 pxTaskBuffer  为        NULL,则不会创建任务,并返回 NULL。

参数说明

pxTaskCode指向任务入口函数的指针(即实现任务的函数名称,请参阅如下示例)。
pcName任务的描述性名称。此参数主要用于获取任务句柄。任务名称的最大长度由 FreeRTOSConfig.h 中的 configMAX_TASK_NAME_LEN 定义。
ulStackDepthpuxStackBuffer 参数用于将 StackType_t 变量数组传递给 xTaskCreateStatic()。必须将 ulStackDepth 设置为数组中的索引数。
pvParameters传递给已创建任务的参数值。如果将 pvParameters 设置为变量的地址,则在创建的任务执行时变量必须仍然存在,因此传递堆栈变量的地址无效。
uxPriority所创建任务执行的优先级。最大是( configMAX_priority - 1)。
puxStackBuffer必须指向至少具有 ulStackDepth 索引的 StackType_t 数组,该数组用作任务的堆栈,因此必须是永久性的(而不是在函数的堆栈上声明)。
pxTaskBuffer必须指向 StaticTask_t 类型的变量。该变量用于保存新任务的数据结构体 (TCB) ,因此必须是持久的(而不是在函数的堆栈中声明)。

实现静态创建任务流程 

  1. 需将宏configSUPPORT_STATIC_ALLOCATION 配置为 1 
  2. 定义空闲任务&定时器任务的任务堆栈及TCB
  3. 实现两个接口函数                                                                                                        vApplicationGetIdleTaskMemory( )                                                        vApplicationGetTimerTaskMemory ( )
  4. 定义函数入口参数
  5. 编写任务函数

官方静态创建任务说明书 

实践代码

/*在freertosfig.h文件中*/
#define configSUPPORT_STATIC_ALLOCATION      1         /* 1: 支持静态申请内存, 默认: 0 */
#define configSUPPORT_DYNAMIC_ALLOCATION     1         /* 1: 支持动态申请内存, 默认: 1 */
#define configMINIMAL_STACK_SIZE             128       
                     /* 定义空闲任务的栈空间大小, 单位: Word, 无默认需定义 */
#define configTIMER_TASK_STACK_DEPTH         ( configMINIMAL_STACK_SIZE * 2) 
                     /* 定义软件定时器任务的栈空间大小, 无默认configUSE_TIMERS为1时需定义 */
/*********************************/

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"

#include "FreeRTOS.h"
#include "task.h"

#define START_TASK_PRIO   1                             //任务优先级为 1
#define START_TASK_STACK_SIZE  128                      //开始任务堆栈定义128 字
TaskHandle_t  start_task_handler;                       //定义任务句柄
StackType_t   start_task_stack[START_TASK_STACK_SIZE];  //定义任务堆栈
StaticTask_t  start_task_tcb;                           //定义任务控制块
void start_task(void * pvParameters);                   //提前声明

#define TASK1_PRIO        2
#define TASK1_STACK_SIZE  128
TaskHandle_t task1_handler;
StackType_t task1_stack[TASK1_STACK_SIZE];
StaticTask_t task1_tcb;
void task1(void * pvParameters);

#define TASK2_PRIO        3
#define TASK2_STACK_SIZE  128
TaskHandle_t task2_handler;
StackType_t task2_stack[TASK2_STACK_SIZE];
StaticTask_t task2_tcb;
void task2(void * pvParameters);

#define TASK3_PRIO        4
#define TASK3_STACK_SIZE  128
TaskHandle_t task3_handler;
StackType_t task3_stack[TASK3_STACK_SIZE];
StaticTask_t task3_tcb;
void task3(void * pvParameters);

StaticTask_t idle_task_tcb;                                  //空闲任务控制块
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];       //空闲任务堆栈

StaticTask_t timer_task_tcb;                                 //软件定时器控制块
StackType_t timer_task_stack[configTIMER_TASK_STACK_DEPTH];  //软件定时器堆栈

//空闲任务内存分配
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
	* ppxIdleTaskTCBBuffer   = &idle_task_tcb;
	* ppxIdleTaskStackBuffer = idle_task_stack;
	* pulIdleTaskStackSize   = configMINIMAL_STACK_SIZE;
}

//软件定时器内存分配
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
                                     StackType_t ** ppxTimerTaskStackBuffer,
                                     uint32_t * pulTimerTaskStackSize )
{
	* ppxTimerTaskTCBBuffer   = &timer_task_tcb;
	* ppxTimerTaskStackBuffer = timer_task_stack;
	* pulTimerTaskStackSize   = configTIMER_TASK_STACK_DEPTH;
}

void freertos_demo(void)
{
 
     start_task_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_handler = xTaskCreateStatic( (TaskFunction_t)    task1,
                                       ( char * )          "task1",
                                       ( uint32_t )        TASK1_STACK_SIZE,
                                       (void * )           NULL,
                                       (UBaseType_t)       TASK1_PRIO,
                                       (StackType_t * )    task1_stack,
                                       (StaticTask_t * )   &task1_tcb 
				                    );
					                         
	task2_handler = xTaskCreateStatic( (TaskFunction_t)    task2,
                                        ( char * )          "task2",
                                        ( uint32_t )        TASK2_STACK_SIZE,
                                        (void * )           NULL,
                                        (UBaseType_t)       TASK2_PRIO,
                                        (StackType_t * )    task2_stack,
                                        (StaticTask_t * )   &task2_tcb 
					                   );

	task3_handler = xTaskCreateStatic( (TaskFunction_t)    task3,
                                       ( char * )          "task3",
                                       ( uint32_t )        TASK3_STACK_SIZE,
                                       (void * )           NULL,
                                       (UBaseType_t)       TASK3_PRIO,
                                       (StackType_t * )    task3_stack,
                                       (StaticTask_t * )   &task3_tcb 
					                  );					   
				                  
    vTaskDelete(start_task_handler);   //使用传入句柄删除函数
	taskEXIT_CRITICAL();               //退出临界区
}
	

//任务一:LED0 500ms翻转一次
void task1(void * pvParameters)
{
	while(1)
	{
		printf("task1正在运行!!!\r\n");
		LED0_TOGGLE();
		vTaskDelay(500);
	}
	
}

//任务二:LED1 500ms翻转一次
void task2(void * pvParameters)
{
	
	while(1)
	{
		printf("task2正在运行!!!\r\n");
		LED1_TOGGLE();
		vTaskDelay(500);
	}
	
}

//任务三:判断按键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)
		{
			vTaskDelete(task1_handler);
			
		}
		vTaskDelay(10);
	}
}

特殊说明

静态创建函数的句柄是静态创建函数的返回值 

任务句柄是一个指向任务控制块(Task Control Block,TCB)的指针

删除任务 

 void  vTaskDelete (TaskHandle_t xTaskToDelete);

功能:

       用于删除已被创建的任务、被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除。

注意:
  1. 当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)
  2. 空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存, 则需要由用户在任务被删除前提前释放,否则将导致内存泄露

删除任务流程 

  1. 使用删除任务函数,需将宏INCLUDE_vTaskDelete 配置为 1
  2. 入口参数输入需要删除的任务句柄(NULL代表删除本身), 传递 NULL 将导致调用任务被删除

推荐博文

FreeRTOS学习笔记02-任务创建和删除(动态方法和静态方法)_rtos 静态创建 动态创建 任务 优缺点-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值