2.FreeRTOS_任务创建与删除

这一次的代码基础是"FreeRTOS_编写调试代码"这篇文章。博客链接如下:

FreeRTOS_编写调试代码-CSDN博客

动态创建任务函数介绍

每一个任务都有自己的栈,动态创建任务就是使用malloc来开辟栈的空间。

函数声明

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
		                const char * const pcName, 
		                const configSTACK_DEPTH_TYPE usStackDepth,
	                    void * const pvParameters,
						UBaseType_t uxPriority,
						TaskHandle_t * const pxCreatedTask )

返回值:创建成功,返回pdPASS

pxTaskCode:函数指针,指向任务的处理函数

pcName:函数名称

usStackDepth:栈的深度,传入100,代表栈大小为100*4字节

pvParameters:参数

uxPriority:优先级,数值越小,优先级越低

pxCreatedTask:句柄,每个任务都被抽象为一个结构体TCB_t,句柄就是指向结构体的指针

使用示例

创建一个任务需要3步:

  • 定义一个句柄
  • 定义一个任务函数
  • 调用任务创建函数

1、定义一个句柄

句柄的类型就是函数声明中句柄的类型:TaskHandle_t,名称以xHandle+任务名定义

具体定义如下:

TaskHandle_t xHandleTask1;

2、定义一个任务函数

在声明中任务函数的类型为:TaskFunction_t,这是一个别名,它实际上的内容如下:

typedef void (* TaskFunction_t)( void * );

因此需要定义一个返回值为void,参数为void*的函数

具体定义如下:

void Task1Function(void *param){
    
    while(1){
		printf("1");
	}
}

3、调用任务创建函数

按照声明的含义,将参数传入任务创建即可。

具体代码如下:

xTaskCreate(Task1Function,"Task1",100,NULL,1,&xHandleTask1);

这代表创建了一个任务,这个任务在Task1Function中去执行,任务名称是Task1,任务的栈有100*4字节,任务函数Task1Function获得的参数是NULL,任务优先级为1,任务的句柄为xHandleTask1

4、整体main函数与执行效果

main函数主要部分如下:

/* 任务处理函数 */
void Task1Function(void *param){
	
	while(1){
	
		printf("1");
		
	}
	
}

int main( void )
{
#ifdef DEBUG
  debug();
#endif
	
	TaskHandle_t xHandleTask1;/* 任务句柄定义 */
	
	prvSetupHardware();
	SerialPortInit();
	printf("UART TEST\r\n");

	xTaskCreate(Task1Function,"Task1",100,NULL,1,&xHandleTask1);/* 创建任务 */
	
	vTaskStartScheduler();
	
	return 0;
}

执行结果如下:

该结果说明,Task1已经被执行。

RTOS任务交叉运行验证

按照上述的方式创建两个任务,一个任务用来打印1,一个任务用来打印2。观察串口输出现象。

main函数主要部分如下:

/* 任务1处理函数 */
void Task1Function(void *param){
	
	while(1){
		printf("1");
	}
}

/* 任务2处理函数 */
void Task2Function(void *param){
	
	while(1){
		printf("2");
	}
}


int main( void )
{
#ifdef DEBUG
  debug();
#endif
	
	TaskHandle_t xHandleTask1;/* 任务1句柄 */
	TaskHandle_t xHandleTask2;/* 任务2句柄 */
	
	prvSetupHardware();
	SerialPortInit();
	printf("UART TEST\r\n");

	xTaskCreate(Task1Function,"Task1",100,NULL,1,&xHandleTask1);/* 创建任务1 */
	xTaskCreate(Task2Function,"Task2",100,NULL,1,&xHandleTask2);/* 创建任务2 */
	
	vTaskStartScheduler();
	
	return 0;
}

执行结果如下:

可以看到,虽然在代码中1和2是跑在两个while中,但实际中1和2是交替打印的。因此验证了RTOS可以实现多任务的功能。

静态创建任务

函数声明

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 )

返回值:句柄,每个任务都被抽象为一个结构体TCB_t,句柄就是指向结构体的指针

pxTaskCode:函数指针,指向任务的处理函数

pcName:函数名称

ulStackDepth:栈的深度,传入100,代表栈大小为100*4字节

pvParameters:参数

uxPriority:优先级,数值越小,优先级越低

puxStackBuffer:栈的内存空间,栈本质就是一片空内存,这里传入数组即可

pxTaskBuffer :指向任务控制块的指针,与句柄作用类似,但类型不一样

相关配置

使用静态任务创建函数时,需自己进行一些配置,具体为以下两步:

  • 开启宏开关
  • 定义空闲任务函数

1、开启宏开关

静态任务创建函数的定义被宏开关控制,默认情况下为关闭,所以需自己在FreeRTOSConfig.h下添加宏。

具体宏如下:

#define configSUPPORT_STATIC_ALLOCATION    1

2、定义空闲任务函数

因为在开启宏开关之后,调度函数中使用到了空闲任务,所以需要自己实现该函数。

函数具体实现如下:

StackType_t xIdleTask3Stack[100];/* 空闲任务的栈 */
StaticTask_t xIdleTask3TCB;      /* 空闲任务的句柄 */
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
	*ppxIdleTaskTCBBuffer = 	&xIdleTask3TCB;    /* 句柄 */
	*ppxIdleTaskStackBuffer = xIdleTask3Stack;     /* 栈 */
	*pulIdleTaskStackSize = 100;                   /* 栈地址 */
}

使用示例

实现了上述的配置,就可以使用静态创建任务函数来创建任务了。具体

1、定义一个栈数组

栈数组的类型为StackType_t ,这是个别名,实质是uint32_t

具体定义如下

StackType_t xTask3Stack[100];

2、定义一个指向任务控制块的指针

指向任务控制块的指针的类型就是函数声明中句柄的类型:pxTaskBuffer ,名称以x任务名+TCB来命名

具体定义如下:

StaticTask_t xTask3TCB;

3、定义一个任务函数

任务函数的定义方法与动态创建任务时一样。

具体的定义如下:

void Task3Function(void *param){
	
	while(1){
		printf("3");
	}
}

4、调用任务创建函数

按照声明的含义,将参数传入任务创建即可。

具体代码如下:

xTaskCreateStatic(Task3Function,"Task3",100,NULL,1,xTask3Stack,&xTask3TCB);

这代表创建了一个任务,这个任务在Task3Function中去执行,任务名称是Task3,任务的栈有100*4字节,任务函数Task3Function获得的参数是NULL,任务优先级为1,任务手动分配的栈空间为xTask3Stack,指向任务控制块的指针为xTask3TCB。

5、整体main函数与执行效果

main函数主要部分如下:

/* 任务3的栈空间与句柄 */
StackType_t xTask3Stack[100];/* 栈 */
StaticTask_t xTask3TCB;      /* 句柄 */


/* 实现空闲任务 */
StackType_t xIdleTask3Stack[100];/* 栈 */
StaticTask_t xIdleTask3TCB;      /* 句柄 */
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
    *ppxIdleTaskTCBBuffer = 	&xIdleTask3TCB;    /* 句柄 */
	*ppxIdleTaskStackBuffer = xIdleTask3Stack;     /* 栈 */
	*pulIdleTaskStackSize = 100;                   /* 栈地址 */
}

/* 3个任务的定义 */
void Task1Function(void *param){
	
	while(1){
		printf("1");
	}
}
void Task2Function(void *param){
	
	while(1){
		printf("2");
	}
}
void Task3Function(void *param){
	
	while(1){
		printf("3");
	}
}


int main( void )
{
#ifdef DEBUG
  debug();
#endif
	
	TaskHandle_t xHandleTask1;
	TaskHandle_t xHandleTask2;
	
	prvSetupHardware();
	SerialPortInit();
	printf("UART TEST\r\n");

    /* 动态创建任务1、任务2 */
	xTaskCreate(Task1Function,"Task1",100,NULL,1,&xHandleTask1);
	xTaskCreate(Task2Function,"Task2",100,NULL,1,&xHandleTask2);

    /* 静态创建任务3 */
	xTaskCreateStatic(Task3Function,"Task3",100,NULL,1,xTask3Stack,&xTask3TCB);

	vTaskStartScheduler();
	
	return 0;
}

执行结果如下:

该结果说明,Task3已经被执行。

删除任务

函数声明

void vTaskDelete( TaskHandle_t xTaskToDelete )

xTaskToDelete:函数创建时,赋值的句柄

杀死自己时传入NULL

使用示例

在静态创建任务的代码基础上,修改任务2的任务函数,使得任务2运行几次之后,杀死任务1;再运行几次之后,杀死自己。

具体代码如下:

/* 改写后的任务2任务函数 */
void Task2Function(void *param){
	
	int i=0;
	
	while(1){
		printf("2");
		i++;
		
		/* 运行15次,杀死任务1 */
		if(i==15){
			vTaskDelete((TaskHandle_t)param);
		}
		
		/* 运行30次,杀死自己 */
		if(i==30){
			vTaskDelete(NULL);
		}
	}
}


/* 改写后的任务2创建函数 */
xTaskCreate(Task2Function,"Task2",100,(void*)xHandleTask1,1,&xHandleTask2);

执行结果如下:

可以看到2打印了一些后,1不再被打印(任务1被删除)。2又打印了一些后,2也不再打印(任务2也被删除)

  • 22
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值