动态创建任务和静态创建任务的区别:
(1)动态创建任务:任务的任务控制块以及任务的栈空间所需的内存均由FreeRTOS从FreeRTOS管理的堆中分配;
(2)静态创建任务:任务的任务控制块以及任务的栈空间所需的内存需要用户分配提供。
开始创建静态任务
1)代码中将宏#define configSUPPORT_STATIC_ALLOCATION配置为1;
#define configSUPPORT_STATIC_ALLOCATION 1 //支持静态内存申请
2)定义配置空闲任务,软件定时器,实现两个接口函数:vApplicationGetIdleTaskMemory、vApplicationGetTimerTaskMemory;
/* 空闲任务任务堆栈 */
static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE];
/* 定时器任务堆栈 */
static StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH];
/* 空闲任务控制块 */
static StaticTask_t Idle_Task_TCB;
/* 定时器任务控制块 */
static StaticTask_t Timer_Task_TCB;
/**
**********************************************************************
* @brief 获取空闲任务的任务堆栈和任务控制块内存
* ppxTimerTaskTCBBuffer : 任务控制块内存
* ppxTimerTaskStackBuffer : 任务堆栈内存
* pulTimerTaskStackSize : 任务堆栈大小
* @date 2018-xx-xx
**********************************************************************
*/
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
StackType_t **ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize)
{
*ppxIdleTaskTCBBuffer=&Idle_Task_TCB;/* 任务控制块内存 */
*ppxIdleTaskStackBuffer=Idle_Task_Stack;/* 任务堆栈内存 */
*pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;/* 任务堆栈大小 */
}
/**
*********************************************************************
* @brief 获取定时器任务的任务堆栈和任务控制块内存
* ppxTimerTaskTCBBuffer : 任务控制块内存
* ppxTimerTaskStackBuffer : 任务堆栈内存
* pulTimerTaskStackSize : 任务堆栈大小
**********************************************************************
*/
void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
StackType_t **ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize)
{
*ppxTimerTaskTCBBuffer=&Timer_Task_TCB;/* 任务控制块内存 */
*ppxTimerTaskStackBuffer=Timer_Task_Stack;/* 任务堆栈内存 */
*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;/* 任务堆栈大小 */
}
3) 定义任务栈
目前我们只创建了一个任务,当任务进入延时的时候,因为没有另外就绪的用户任务, 那么系统就会进入空闲任务,空闲任务是 FreeRTOS 系统自己启动的一个任务,优先级最低。当整个系统都没有就绪任务的时候,系统必须保证有一个任务在运行,空闲任务就是 为这个设计的。当用户任务延时到期,又会从空闲任务切换回用户任务。 在 FreeRTOS 系统中,每一个任务都是独立的,他们的运行环境都单独的保存在他们 的栈空间当中。那么在定义好任务函数之后,我们还要为任务定义一个栈,目前我们使用 的是静态内存,所以任务栈是一个独立的全局变量。任务的栈占用 的是 MCU 内部的 RAM,当任务越多的时候,需要使用的栈空间就越大,即需要使用的 RAM 空间就越多。一个 MCU 能够支持多少任务,就得看你的 RAM 空间有多少。
/* AppTaskCreate任务任务堆栈 */
static StackType_t AppTaskCreate_Stack[128];
/* LED任务堆栈 */
static StackType_t LED_Task_Stack[128];
4)定义任务控制块
定义好任务函数和任务栈之后,我们还需要为任务定义一个任务控制块,通常我们称 这个任务控制块为任务的身份证。在 C代码上,任务控制块就是一个结构体,里面有非常 多的成员,这些成员共同描述了任务的全部信息,
/* AppTaskCreate 任务控制块 */
static StaticTask_t AppTaskCreate_TCB;
/* AppTaskCreate 任务控制块 */
static StaticTask_t LED_Task_TCB;
5) 静态创建任务
一个任务的三要素是任务主体函数,任务栈,任务控制块,那么怎么样把这三个要素 联合在一起?FreeRTOS 里面有一个叫静态任务创建函数 xTaskCreateStatic(),它就是干这个活的。它将任务主体函数,任务栈(静态的)和任务控制块(静态的)这三者联系在一 起,让任务可以随时被系统启动,
/* 创建 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(); /* 启动任务,开启调度 */
6) 启动任务
当任务创建好后,是处于任务就绪(Ready),在就绪态的任务可以参与操作系统的调度。 但是此时任务仅仅是创建了,还未开启任务调度器,也没创建空闲任务与定时器任务(如果使 能了 configUSE_TIMERS 这个宏定义),那这两个任务就是在启动任务调度器中实现,每个操作系统,任务调度器只启动一次,之后就不会再次执行了,FreeRTOS 中启动任务调度器的函 数是 vTaskStartScheduler(),并且启动任务调度器的时候就不会返回,从此任务管理都由 FreeRTOS管理,此时才是真正进入实时操作系统中的第一步,
vTaskStartScheduler(); /* 启动任务,开启调度 */