二、freeRTOS_创建任务函数详解

目录

1. 动态内存的使用

2. 静态创建任务

portmacro.h

freeRTOS.h 

tasks.c

main.c

2.运行结果

3. 进一步实验

3.1 优先级实验

3.1 运行结果

3.2 删除任务

3.2 运行结果

3.3 使用同一个任务函数创建多个任务

3.3 运行结果

3.4 栈大小实验

3.4 运行结果


1. 动态内存的使用

  • 怎么表示任务?

    • 以面向对象的思想:任务控制块

    • 可以动态分配

  • 多任务的核心:栈,可以动态分配

  • xTaskCreate:该函数可以动态创建任务,细节可以看源码。

2. 静态创建任务

对应程序:06_freertos_example_createtaskstatic

  • 事先分配好任务控制块

  • 事先提供栈

  • xTaskCreateStatic:该函数可以静态创建任务

portmacro.h

    #define portSTACK_TYPE    uint32_t

    typedef portSTACK_TYPE   StackType_t;

freeRTOS.h 

typedef struct xSTATIC_TCB
{
    ...
} StaticTask_t;

对于嵌入式系统,内部的资源都是很有限,如果该函数不是非必须的,我们就用某些开关决定是否开启它,比如:#if ( configSUPPORT_STATIC_ALLOCATION == 1 )

tasks.c

#if ( configSUPPORT_STATIC_ALLOCATION == 1 )

    TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
                                    const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                                    const uint32_t ulStackDepth,
                                    void * const pvParameters,
                                    UBaseType_t uxPriority,
                                    StackType_t * const puxStackBuffer,
                                    StaticTask_t * const pxTaskBuffer )

main.c

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

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

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


/*-----------------------------------------------------------*/

StackType_t xTask3Stack[100];
StaticTask_t xTask3TCB;

StackType_t xIdleTaskStack[100];
StaticTask_t xIdleTaskTCB;


/*
 * The buffers used here have been successfully allocated before (global variables)
 */
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
    *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
    *ppxIdleTaskStackBuffer = xIdleTaskStack;
    *pulIdleTaskStackSize = 100;
}


int main( void )
{
	TaskHandle_t xHandleTask1;
		
#ifdef DEBUG
  debug();
#endif

	prvSetupHardware();

	printf("Hello, world!\r\n");

	xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
	xTaskCreateStatic(Task3Function, "Task3", 100, NULL, 1, xTask3Stack, &xTask3TCB);

	/* Start the scheduler. */
	vTaskStartScheduler();

	/* Will only get here if there was not enough heap space to create the
	idle task. */
	return 0;
}

2. 运行结果

在同等优先级下,动态和静态创建的任务是交替执行的,这是一种调度机制。

二、freeRTOS_创建任务函数详解_第1张图片

3. 进一步实验

对应程序:07_freertos_example_test

  • 优先级实验

  • 删除任务

  • 使用同一个任务函数创建多个任务

  • 栈大小实验

3.1 优先级实验

TaskHandle_t xHandleTask1;

static int task1flagrun = 0;
static int task2flagrun = 0;
static int task3flagrun = 0;

void Task1Function(void * param)
{	
	while (1)
	{
		task1flagrun = 1;
		task2flagrun = 0;
		task3flagrun = 0;
		printf("1");
	}
}

void Task2Function(void * param)
{	
	while (1)
	{
		task1flagrun = 0;
		task2flagrun = 1;
		task3flagrun = 0;
		printf("2");
	}
}

void Task3Function(void * param)
{
	while (1)
	{
		task1flagrun = 0;
		task2flagrun = 0; 
		task3flagrun = 1;
		printf("3");
	}
}

/*-----------------------------------------------------------*/

StackType_t xTask3Stack[100];
StaticTask_t xTask3TCB;

StackType_t xIdleTaskStack[100];
StaticTask_t xIdleTaskTCB;


/*
 * The buffers used here have been successfully allocated before (global variables)
 */
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
    *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
    *ppxIdleTaskStackBuffer = xIdleTaskStack;
    *pulIdleTaskStackSize = 100;
}


int main( void )
{		
	prvSetupHardware();

	printf("Hello, world!\r\n");

	xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
	xTaskCreateStatic(Task3Function, "Task3", 100, NULL, 1, xTask3Stack, &xTask3TCB);

	/* Start the scheduler. */
	vTaskStartScheduler();

	/* Will only get here if there was not enough heap space to create the
	idle task. */
	return 0;
}

3.1 运行结果

三个任务都是交替执行,在同一时间,只有一个高电平在运行。

二、freeRTOS_创建任务函数详解_第2张图片

 串口1打印的数据,也是交替执行。

 如果我把任务1的优先级提高到2,在来看一下运行的结果吧!

	xTaskCreate(Task1Function, "Task1", 100, NULL, 2, &xHandleTask1);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
	xTaskCreateStatic(Task3Function, "Task3", 100, NULL, 1, xTask3Stack, &xTask3TCB);

此时,只有高任务的优先级先执行,如果高任务的优先级没有主动放弃任务的话,其他低优先级的任务根本没有办法执行,从下图来看,只有任务1为高电平,其他都为低电平

二、freeRTOS_创建任务函数详解_第3张图片

 串口1打印的数据,也是任务1在执行。二、freeRTOS_创建任务函数详解_第4张图片

3.2 删除任务

把3.1实验的优先级都写为1,然后,Task2Function的代码修改如下即可,使用vTaskDelete删除任务。

删除其他任务时写入对应任务的句柄,如vTaskDelete(xHandleTask1);(动态/静态都有自己的句柄,只不过静态会返回一个句柄如TaskHandle_t xTaskCreateStatic())。

删除自己时,如vTaskDelete(xHandleTask1);

void Task2Function(void * param)
{
	int i = 0;
	
	while (1)
	{
		task1flagrun = 0;
		task2flagrun = 1;
		task3flagrun = 0;
		printf("2");

		if (i++ == 100)
		{
			vTaskDelete(xHandleTask1);
		}

		if (i == 200)
		{
			vTaskDelete(NULL);
		}

	}
}

3.2 运行结果

开始任务3,任务1,任务2交替执行,i++ = 100之后任务2杀死任务1,i == 200之后,杀死自己,之后,就只有任务3在运行。

二、freeRTOS_创建任务函数详解_第5张图片

3.3 使用同一个任务函数创建多个任务

使用同一个TaskGenericFunction函数,创建不同的任务,一个函数之所有能创建不同的任务,是因为他们的栈不一样,运行时候互补影响。

void TaskGenericFunction(void * param)
{
	int val = (int)param;
	while (1)
	{
		printf("%d", val);
	}
}

......

int main(){

......
	xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
	xTaskCreateStatic(Task3Function, "Task3", 100, NULL, 1, xTask3Stack, &xTask3TCB);

	xTaskCreate(TaskGenericFunction, "Task4", 100, (void *)4, 1, NULL);
	xTaskCreate(TaskGenericFunction, "Task5", 100, (void *)5, 1, NULL);
......

}

3.3 运行结果

任务5 1 2 3 4交替执行

二、freeRTOS_创建任务函数详解_第6张图片

3.4 栈大小实验

我们使用malloc函数,在堆上(heap)申请一块内存,长度为len,我们在使用free函数时,可以得到buf的首地址,但是并没有得到长度啊?我们怎么可以得到这个长度len呢?这个长度len保存在哪里?

答:一般来说,保存在buf的前面,前面有一个结构体,这个结构体至少有长度信息,当我使用free函数时,反过来就知道长度信息是多少了。

二、freeRTOS_创建任务函数详解_第7张图片

二、freeRTOS_创建任务函数详解_第8张图片

任务1的栈只有400字节,但是申请了500字节,就会把任务1的栈给撑爆,结果见下面运行结果。

void Task1Function(void * param)
{
	volatile char buf[500];
	int i;
	
	while (1)
	{
		task1flagrun = 1;
		task2flagrun = 0;
		task3flagrun = 0;
		printf("1");

		for ( i = 0; i < 500; i++)
		buf[i] = 0;
	}
}

3.4 运行结果

STM32F10x.s,在汇编文件中提示,硬件错误。

 运行结果出现异常,程序崩了,后续在使用栈时,要谨慎使用!!!

你可能感兴趣的:(freeRTOS_实战,stm32)