八、任务的创建与删除

1、任务的三要素:主体函数、任务栈、任务控制块。

重要:每个任务中所有局部变量占用的空间必须要比其栈空间小,否则可能会出现这个任务内存的溢出而影响其他任务。

2、与任务相关的部分API函数

(1)xTaskCreate

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
                       const char * const pcName, // 任务的名字
                       const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为 word,10 表示40 字节
                       void * const pvParameters, // 调用任务函数时传入的参数
                       UBaseType_t uxPriority, // 优先级
                       TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务

在这里插入图片描述

(2)void vTaskDelete( TaskHandle_t xTaskToDelete )

在这里插入图片描述

3、任务的创建

(1)使用静态任务创建函数进行任务创建(使用这个函数创建任务后,会返回一个任务句柄,这个句柄实际上就是一个指针,指向对应任务的任务控制块这个结构体)

即任务使用的栈和任务控制块都事先定义好,即使用的是静态内存。

1)定义任务函数

任务函数实际为一个无限循环且不带返回值的函数。
且在任务函数里面尽量使用局部变量。

2)定义任务栈(这个是静态创建时需要进行的,即静态创建的时候任务控制块和栈空间都需要先定义好)

	 /* 定义LED 任务堆栈 */
	static StackType_t LED_Task_Stack[128];

3)定义任务控制块

	/* AppTaskCreate 任务控制块 */
	static StaticTask_t AppTaskCreate_TCB;
	/* AppTaskCreate 任务控制块 */
	static StaticTask_t LED_Task_TCB;

4)使用xTaskCreateStatic来创建一个任务

int main(void)
{	
  /* 开发板硬件初始化 */
  BSP_Init();
  /* 创建 AppTaskCreate 任务 */
 AppTaskCreate_Handle = xTaskCreateStatic((TaskFunction_t	)AppTaskCreate,		//任务函数
															(const char* 	)"AppTaskCreate",	//任务名称
															(uint32_t 		)128,				//任务堆栈大小
															(void* 		  	)NULL,		//传递给任务函数的参数
															(UBaseType_t 	)3, 			//任务优先级
															(StackType_t*   )AppTaskCreate_Stack,  //任务堆栈
															(StaticTask_t*  )&AppTaskCreate_TCB);//任务控制块   
															
	if(NULL != AppTaskCreate_Handle)/* 创建成功 */
    vTaskStartScheduler();   /* 启动任务,开启调度 */
  
  while(1);   /* 正常不会执行到这里 */    
}



static void AppTaskCreate(void)
{
	taskENTER_CRITICAL();           //进入临界区

	/* 创建LED_Task任务 */
	LED_Task_Handle = xTaskCreateStatic((TaskFunction_t	)LED_Task,		//任务函数
														(const char* 	)"LED_Task",	//任务名称
														(uint32_t 		)128,			//任务堆栈大小
														(void* 		  	)NULL,			//传递给任务函数的参数
														(UBaseType_t 	)4, 				//任务优先级
														(StackType_t*   )LED_Task_Stack,	//任务堆栈
														(StaticTask_t*  )&LED_Task_TCB);	//任务控制块   

if(NULL != LED_Task_Handle)/* 创建成功 */
	printf("LED_Task任务创建成功!\n");
else
	printf("LED_Task任务创建失败!\n");

 vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务

 taskEXIT_CRITICAL();            //退出临界区
}

任务创建成功后,是处于任务就绪状态,此时任务可以参与操作系统的调度。
若此时还没有开启调度任务就不会被执行。上面在主函数创建任务成功之后开启了调度器。

(2)使用动态任务创建函数进行任务创建(使用这个函数创建任务时,需要传进去预先定义好的任务句柄)

动态内存空间的堆

FreeRTOS在SRAM里面定义一个大数组,即堆内存,供FreeRTOS的动态分配函数使用。
在第一次使用时系统会将堆内存进行初始化。例如

//系统所有总的堆大小
#define configTOTAL_HEAP_SIZE ((size_t)(36*1024))
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
/* 如果这是第一次调用 malloc 那么堆将需要
初始化,以设置空闲块列表。*/
if ( pxEnd == NULL ){
	prvHeapInit(); 
} 
else
{
	mtCOVERAGE_TEST_MARKER();
}

1)定义任务函数

任务函数实际为一个无限循环且不带返回值的函数。
且在任务函数里面尽量使用局部变量。

2)定义任务句柄(作为任务创建时创进去的实参,创建成功后其指向的是任务控制块)

使用动态任务创建函数的时候,最后一个参数传递的是对应任务的任务句柄的地址,即这个动态任务创建函数的返回值是一个是否成功创建任务的信息,所以需要传进去一个任务句柄,这个任务句柄指向的还是对应任务的任务控制块。

/* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED 任务句柄 */
static TaskHandle_t LED_Task_Handle = NULL;

3)使用xTaskCreate()函数来创建一个任务。

int main(void)
{
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	
	/* 开发板硬件初始化 */
	BSP_Init();
	printf("这是一个[野火]-STM32 全系列开发板-FreeRTOS-工程模板!\r\n");
	/* 创建 AppTaskCreate 任务 */
	xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */
							(const char* )"AppTaskCreate",/* 任务名字 */
							(uint16_t )512, /* 任务栈大小 */
							(void* )NULL,/* 任务入口函数参数 */
							(UBaseType_t )1, /* 任务的优先级 */
							(TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针 */
	/* 启动任务调度 */
	if (pdPASS == xReturn)
		vTaskStartScheduler(); /* 启动任务,开启调度 */
	else
	return -1;

	while (1); /* 正常不会执行到这里 */
	}


static void AppTaskCreate(void)
{
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */

	taskENTER_CRITICAL(); //进入临界区

	/* 创建 LED_Task 任务 */
	xReturn = xTaskCreate((TaskFunction_t )LED_Task, /* 任务入口函数 */
							(const char* )"LED_Task",/* 任务名字 */
							(uint16_t )512, /* 任务栈的深度,实际栈空间的大小为512*4个字节 */
							(void* )NULL, /* 任务入口函数参数 */
							(UBaseType_t )2, /* 任务的优先级 */
							(TaskHandle_t* )&LED_Task_Handle);/* 任务控制块指针 */
if (pdPASS == xReturn)
	printf("创建 LED_Task 任务成功!\r\n");

vTaskDelete(AppTaskCreate_Handle); //删除 AppTaskCreate 任务

taskEXIT_CRITICAL(); //退出临界区
}

4、任务的删除vTaskDelete(xHandle Taskx)

需要使用到任务创建时的任务句柄。即这个函数需要传递的参数是任务句柄

对于静态创建任务函数来说它的返回值为其任务句柄;而动态创建任务函数是吧定义好的任务句柄作为实参的,也可以为空即NULL。

当这个函数传入的参数为NULL时表示删除自身任务。

5、需要注意的几个点

(1)任务创建成功后对任务的各种操作都是通过任务句柄来实现的

(2)可以使用同一个函数创建两个任务(这时候因为两个函数的栈不一样,所以他们互不影响)

在这里插入图片描述

6、动态创建任务函数解析

(1)创建任务时的入口函数在定义中的形参可以是 void *类型,表示的是可以传递任何类型的参数

(2)任务函数里面的局部变量是存放在对应任务的栈空间里面的

(3)如何大概确定栈的大小:栈的大小取决于局部变量的大小和调用深度(即任务里面的调用函数的关系)传递进来的栈的深度为N,但实际上这个栈具有4N字节空间

(4)栈是从哪里分配出来的:动态创建时每个任务的栈是从一个预先分配好的巨大的数据(堆)中分配的,这个数组的大小可以用户自己设置,具体如下图

(5)使用动态创建任务时,第一个参数为任务函数入口,即任务需要执行函数的地址,当任务执行的时候即让PC寄存器的值等于这个函数地址;
在这里插入图片描述

(6)这个函数为对应若任务分配了TCB结构体、栈,并在栈里写入了函数地址、参数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值