目录
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 运行结果
怎么表示任务?
以面向对象的思想:任务控制块
可以动态分配
多任务的核心:栈,可以动态分配
xTaskCreate:该函数可以动态创建任务,细节可以看源码。
对应程序:06_freertos_example_createtaskstatic
事先分配好任务控制块
事先提供栈
xTaskCreateStatic:该函数可以静态创建任务
#define portSTACK_TYPE uint32_t
typedef portSTACK_TYPE StackType_t;
typedef struct xSTATIC_TCB
{
...
} StaticTask_t;
对于嵌入式系统,内部的资源都是很有限,如果该函数不是非必须的,我们就用某些开关决定是否开启它,比如:#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
#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 )
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;
}
在同等优先级下,动态和静态创建的任务是交替执行的,这是一种调度机制。
对应程序:07_freertos_example_test
优先级实验
删除任务
使用同一个任务函数创建多个任务
栈大小实验
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;
}
三个任务都是交替执行,在同一时间,只有一个高电平在运行。
如果我把任务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为高电平,其他都为低电平
把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,任务1,任务2交替执行,i++ = 100之后任务2杀死任务1,i == 200之后,杀死自己,之后,就只有任务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);
......
}
任务5 1 2 3 4交替执行
我们使用malloc函数,在堆上(heap)申请一块内存,长度为len,我们在使用free函数时,可以得到buf的首地址,但是并没有得到长度啊?我们怎么可以得到这个长度len呢?这个长度len保存在哪里?
答:一般来说,保存在buf的前面,前面有一个结构体,这个结构体至少有长度信息,当我使用free函数时,反过来就知道长度信息是多少了。
任务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;
}
}
STM32F10x.s,在汇编文件中提示,硬件错误。
运行结果出现异常,程序崩了,后续在使用栈时,要谨慎使用!!!