第四章 FreeRTOS的任务创建与删除

目录

一. 任务控制块结构成员介绍 

二.  任务的删除

2.1 任务删除函数 

2.2 删除任务流程

2.3 删除任务内部实现流程

三.  动态创建任务

3.1 动态创建任务函数

3.2 动态创建任务流程

3.3 动态创建任务的内部实现方式(简易描述)

四.  静态创建任务

4.1静态创建任务函数

4.2 静态创建任务流程

4.3静态创建任务的内部实现方式(简易描述)


一. 任务控制块结构成员介绍 

认识:  任务控制块是一个结构体,结构体存在很多的成员变量,就好比任务的身份证,保留了任务的一些特征。

typedef struct tskTaskControlBlock       
{
    volatile StackType_t     * pxTopOfStack;  
   	ListItem_t               xStateListItem;     
	ListItem_t               xEventListItem;
    UBaseType_t     		 uxPriority; 
    StackType_t 	    	 * pxStack;	
    char 			         pcTaskName[ configMAX_TASK_NAME_LEN ];
	…
	省略很多条件编译的成员
} tskTCB;

参数介绍

*pxTopOfStack:

任务栈栈顶。必须为TCB的第一个成员,因为和任务切换、任务上下文保存、任务恢复都息息相关。


xStateListItem:

任务状态列表项。任务处于的状态保存在此参数中,比如:运行态、就绪态、挂起态、阻塞态。


xEventListItem:

任务事件列表项。如果当前正在等待某些事件,就会用到此参数。


uxPriority:

任务优先级。数值越大,优先级越大。当前任务的优先级存在此参数中。


*pxStack:

任务堆栈的首地址


pcTaskName[ configMAX_TASK_NAME_LEN ]:

任务名字。

二.  任务的删除

2.1 任务删除函数 

void vTaskDelete(TaskHandle_t xTaskToDelete);

参数介绍

xTaskToDelete:待删除任务的任务句柄

比如给我们创建了一个任务,任务是具有任务句柄的,删除任务就需要将任务句柄传入此函数就可以删除任务了。


① 此函数用于删除已经被创建成功的任务,如果没有被创建,是不能被删除的。

② 被删除的任务将从就绪态任务列表、阻塞态任务列表、 挂起态任务列表和事件列表中移除(不管任务处于何种状态,只要调用删除函数vTaskDelete(),传入需要删除的任务的句柄,那么都会被删除)。

③ 当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)。

④ 区别:

        1. 针对动态创建空闲任务会负责释放被删除任务中被系统分配的内存(删除自身任务,即函数xTaskDelete()传入NULL时,才会利用空闲任务释放掉被删除任务使用的系统分配的内存,如果是在task1任务中删除task2,则在task1中释放task2所使用的内存空间。

        2. 针对静态创建由用户在任务删除前申请的内存,则需要用户在任务被删除前提前释放,否则将导致内存泄露。


2.2 删除任务流程

① 使用删除任务函数,需将宏INCLUDE_vTaskDelete配置为1

入口参数输入需要删除的任务句柄NULL代表删除本身)。


2.3 删除任务内部实现流程

1、获取所要删除任务的控制块:通过传入的任务句柄,判断所需要删除哪个任务,NULL代表删除自身。(找到所需要删除任务的任务控制块)

2、将被删除任务,在所在列表中移除:将该任务在所在列表中移除,包括:就绪、阻塞、挂起、事件等列表。

3、判断所需要删除的任务:删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务执行;删除其他任务,释放内存,任务总数量减1。

4、更新下个任务的阻塞时间:更新下一个任务的阻塞超时时间,以防被删除的任务就是下一个阻塞超时的任务。

比如有3个任务,task1、task2、task3, task2及task3进入阻塞态,task2阻塞延时20ms,task3阻塞延时50ms,task2和task3会挂载到阻塞列表中,时间短的task2会放在task3前面,此时肯定是20ms的task2先到,时间到了将task2放入就绪列表,如果在task1中删除的任务刚好为task2,不管task2在何种状态都将被移除,而阻塞时间还是20ms,则需要更新成下一个阻塞时间50ms。

三.  动态创建任务

认识:任务的任务控制块以及任务的栈空间所需的内存,均由FreeRTOS从FreeRTOS管理的堆中分配,不需要人为操作。

3.1 动态创建任务函数


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 	/* 任务句柄,就是任务的任务控制块 */
)

参数介绍 

pxTaskCode:

指向任务函数的指针。比如创建了一个任务,任务所需要实现的功能全部放在任务函数中,通过此参数指向任务函数。


pcName:

任务名字。名字长度由FreeRTOSConfig.h中的宏configMAX_TASK_NAME_LEN决定,默认为16字符长度。


usStackDepth:

任务堆栈大小,注意单位是“字”。例如堆大小为100,则实际大小为100×4=400字节。


pvParameters:

传递给任务函数的参数。一般用不到,传入空(NULL)。


uxPriority:

任务优先级。每个任务都有自己的优先级,具体范围是0~configMAX_PRIORITIES - 1,宏定义在FreeRTOSConfig中设置。在程序中设置的为32,并且任务优先级越大,任务就越优先。


pxCreatedTask:

任务句柄。删除任务是通过任务句柄进行操作,任务句柄其实就是任务的任务控制块。在函数内部任务控制块等效于任务句柄。

函数返回值描述
pdPASS任务创建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY任务创建失败(其中MEMORY,主要是指任务堆栈过大,动态创建是在FreeRTOS管理的堆空间中创建,如果超出了堆空间大小,则会创建失败

3.2 动态创建任务流程

① 将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1;

② 定义函数的入口参数(可以提前定义,任务创建时代入);

③ 编写任务函数(任务需要实现的功能,在任务函数中完成);

注: 使用xTaskCreat()函数创建的任务会立即进入就绪态,由任务调度器调度运行。比如说创建了很多任务,这些任务创建后会立刻进入就绪态,由任务调度器在就绪态中找到任务优先级最高的去执行。


3.3 动态创建任务的内部实现方式(简易描述)

申请任务堆栈和任务控制块的内存(只需要定义所申请的大小,之后由FreeRTOS自动地去申请);

TCB结构体成员赋值(TCB,任务控制块。类似于人的身份证,每个任务都有自己的任务控制块,任务控制块存取任务的一些特征,比如任务名、优先级、状态等);

添加新任务到就绪列表中(任务进入到就绪态)。

3.4 示例代码

/*START任务的基本配置*/
#define START_STK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t	start_task_handler;
void StartTask_fun(void);

void Demo()
{
	xTaskCreate((TaskFunction_t	)	StartTask_fun,		//任务函数	
				(char * 		) 	"StartTask_fun",	//任务名字
				(uint16_t		) 	START_STK_SIZE,		//堆栈大小
				(void * 		) 	NULL,				//任务参数
				(UBaseType_t	) 	START_TASK_PRIO,	//任务优先级
				(TaskHandle_t *	) 	&start_task_handler);//任务句柄
				
	vTaskStartScheduler();          //开启任务调度
}

/*任务函数*/
void StartTask_fun()
{
    while(1)
    {
        printf("hello freertos\r\n");    
    }
}

四.  静态创建任务

认识:任务的任务控制块以及任务的栈空间所需的内存,需要用户分配提供。(人为地定义内存,比如说定义一个数组当作任务栈空间)

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

参数介绍

其他参数与动态创建任务的类似。有区别的为以下两个:

puxStackBuffer:

任务堆栈。一般为数组,由用户自己定义(这里和动态创建有区别,动态创建只需要指定任务堆栈大小ulStackDepth,剩下的是由FreeRTOS根据任务大小,自动去申请堆大小,而静态需要给定数组地址)。

pxTaskBuffer:

任务控制块指针。指向任务控制块的地址,任务控制块保留了很多信息,信息需要内存来保存,这部分内存也需要用户自己分配。

函数返回值

描述
NULL用户没有提供相应的内存,任务创建失败。(比如说任务堆栈puxStackBuffer参数并没有指定,那么就会创建失败)
其他值任务句柄,任务创建成功

4.2 静态创建任务流程

注:静态创建任务函数xTaskCreatStatic()创建的任务会立刻进入就绪态,由任务调度器进行调度。

① 需将宏configSUPPORT_STATIC_ALLOCATION配置为1

定义空闲任务定时器任务的任务堆栈及TCB

注:

        空闲任务是得必须有在RTOS中CPU是不能停止的,在空闲时需要执行空闲任务

        定时器任务是可选的当使能了软件定时器功能,这个任务就需要被创建,如果没有被使能,就不需要创建软件定时器任务,

        这两个任务都是静态创建,用户都需要分配任务堆栈和任务控制块

实现两个接口函数

第一个是空闲任务的内存赋值vApplicationGetldleTaskMemory();

第二个是定时器的内存赋值vApplicationGetTimerTaskMemory();

由于在第2步任务堆栈、任务控制块需要赋值给结构体成员,就通过这两个函数来实现。

定义函数入口参数

编写任务函数


4.3静态创建任务的内部实现方式(简易描述)

TCB结构体成员赋值(将任务的一些特征赋值给任务控制块TCB)

添加新任务到就绪列表中

4.4 示例代码

/*定义空闲任务(必须)*/
StaticTask_t	idle_task_tcb;
StackType_t 	idle_task_stack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory(	StaticTask_t **ppxIdleTaskTCBBuffer, 
									StackType_t **ppxIdleTaskStackBuffer,
									uint32_t *pulIdleTaskStackSize )
{
	*ppxIdleTaskTCBBuffer = &idle_task_tcb;
	*ppxIdleTaskStackBuffer = idle_task_stack;
	*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}

/*定义定时器任务(可选)*/
StaticTask_t	timer_task_tcb;
StackType_t 	timer_task_stack[configTIMER_TASK_STACK_DEPTH];

void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, 
									 StackType_t **ppxTimerTaskStackBuffer, 
									 uint32_t *pulTimerTaskStackSize )
{
	*ppxTimerTaskTCBBuffer = &timer_task_tcb;
	*ppxTimerTaskStackBuffer = timer_task_stack;
	*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}

/*START任务的基本配置*/
#define START_STK_SIZE 128
#define START_TASK_PRIO 1
TaskHandle_t	start_task_handler;
StackType_t     start_task_stack[START_STK_SIZE];
StaticTask_t    start_task_tcb;
void StartTask_fun(void);

void Demo()
{
	start_task_handler = xTaskCreateStatic(	(TaskFunction_t	) 	StartTask_fun,
											(char *  		)	"StartTask_fun",
											(uint32_t		) 	START_STK_SIZE,
											(void * 		)	NULL,
											(UBaseType_t 	)	START_TASK_PRIO,
											(StackType_t *	)  	start_task_stack,
											(StaticTask_t *	) 	&start_task_tcb );
				
	vTaskStartScheduler();          //开启任务调度
}

void StartTask_fun()
{
    while(1)
    {
        printf("hello freertos\r\n");
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值