任务的创建和删除分为动态方式和静态方式两种
动态创建任务:
任务的任务控制块以及任务的栈空间所需的内存,均由 FreeRTOS 从 FreeRTOS 管理的堆中分配(用户仅指定stack大小)
静态创建任务:
任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供
什么是临界区保护
答:临界区保护,保护那些不想被打断的程序段,关闭freertos所管理的中断,中断无法打断,滴答中断和PendSV中断无法进行不能实现任务调度 。
动态创建优点
答:动态创建使用起来相对简单。在实际的应用中,动态方式创建任务是比较常用的,除非有特殊的需求,一般都会使用动态方式创建任务 。
静态创建优点
答:静态创建可将任务堆栈放置在特定的内存位置,并且无需关心对内存分配失败的处理 。
动态创建任务简要流程
主程序()
{
创建start_task
vTaskStartScheduler();//开启调度器
}
start_task()
{
*taskENTER_CRITICAL();//进入临界区*
创建task1、task2……
vTaskDelete(NULL);
taskEXIT_CRITICAL();//退出临界区
}
动态创建任务
-
将宏配置为configSUPPORT_DYNAMIC_ALLOCATION 1(FreeRTOSConfig.h中):开启动态分配
-
定义函数的入口参数
- pxTaskCode :指向任务函数的指针
- pcName : 任务名字,最大长度configMAX_TASK_NAME_LEN
- usStackDepth :任务堆栈大小,注意字为单位(内部*4)
- pvParameters :传递给任务函数的参数(常用NULL)
- uxPriority :任务优先级,范围:0 ~ configMAX_PRIORITIES - 1
- pxCreatedTask :任务句柄,就是任务的任务控制块
-
编写任务函数
任务代码
此函数创建的任务会立刻进入就绪态,由任务调度器调度运行
以下为动态创建任务函数内部实现(了解)
-
申请堆栈内存&任务控制块内存
-
TCB结构体成员赋值
-
添加新任务到就绪列表中

附动态分配基础代码
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1 /* 任务优先级 */
#define START_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; /* 任务句柄 */
void start_task(void *pvParameters); /* 任务函数 */
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t TASK1_Handler; /* 任务句柄 */
void TASK1(void *pvParameters); /* 任务函数 */
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3 /* 任务优先级 */
#define TASK2_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t TASK2_Handler; /* 任务句柄 */
void TASK2(void *pvParameters); /* 任务函数 */
/* TASK3 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK3_PRIO 4 /* 任务优先级 */
#define TASK3_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t TASK3_Handler; /* 任务句柄 */
void TASK3(void *pvParameters); /* 任务函数 */
void freertos_demo(void)
{
xTaskCreate((TaskFunction_t )start_task, /* 任务函数 */
(const char* )"start_task", /* 任务名称 */
(uint16_t )START_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )START_TASK_PRIO, /* 任务优先级 */
(TaskHandle_t* )&StartTask_Handler); /* 任务句柄 */
vTaskStartScheduler();
}
void start_task(void *pvParameters)
{
taskENTER_CRITICAL();
xTaskCreate((TaskFunction_t )TASK1, /* 任务函数 */
(const char* )"TASK1", /* 任务名称 */
(uint16_t )TASK1_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK1_PRIO, /* 任务优先级 */
(TaskHandle_t* )&TASK1_Handler); /* 任务句柄 */
xTaskCreate((TaskFunction_t )TASK2, /* 任务函数 */
(const char* )"TASK2", /* 任务名称 */
(uint16_t )TASK2_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK2_PRIO, /* 任务优先级 */
(TaskHandle_t* )&TASK2_Handler); /* 任务句柄 */
xTaskCreate((TaskFunction_t )TASK3, /* 任务函数 */
(const char* )"TASK3", /* 任务名称 */
(uint16_t )TASK3_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK3_PRIO, /* 任务优先级 */
(TaskHandle_t* )&TASK3_Handler); /* 任务句柄 */
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
void TASK1(void *pvParameters)
{
while(1)
{
printf("task1 ruing!!!\n");
LED0_TOGGLE();
vTaskDelay(500);
}
}
void TASK2(void *pvParameters)
{
while(1)
{
printf("task2 ruing!!!\n");
LED1_TOGGLE();
vTaskDelay(250);
}
}
void TASK3(void *pvParameters)
{
uint8_t key=0;
while(1)
{
printf("task3 ruing!!!\n");
key=key_scan(0);
if(key==KEY0_PRES)
{
if(TASK1_Handler!=NULL)
{
printf("delete task1 \n");
vTaskDelete(TASK1_Handler);
TASK1_Handler = NULL;
}
}
vTaskDelay(50);
}
}
任务删除函数
void vTaskDelete(TaskHandle_t xTaskToDelete);
| 形参 | 描述 |
|---|---|
| xTaskToDelete | 待删除任务的任务句柄 |
用于删除已被创建的任务
被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除
-
当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)
-
空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存, 则需要由用户在任务被删除前提前释放,否则将导致内存泄
-
需将宏INCLUDE_vTaskDelete 配置为 1(FreeRTOSConfig.h中):开启任务删除
-
入口参数输入要删除的任务句柄(NULL代表删除任务本身)
vTaskDelete(NULL);

静态创建任务
-
将宏configSUPPORT_STATIC_ALLOCATION 配置为 1
-
定义空闲任务&定时器任务的任务堆栈及TCB
-
空闲任务配置
StaticTask_t idle_task_tcb; StackType_t idle_task_stack[configMINIMAL_STACK_SIZE]; -
定时器任务配置
StaticTask_t timer_task_tcb; StackType_t timner_task_stack[configTIMER_TASK_STACK_DEPTH];
-
-
实现两个接口函数
-
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, StackType_t ** ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) { * ppxIdleTaskTCBBuffer=&idle_task_tcb; * ppxIdleTaskStackBuffer=idle_task_stack; * pulIdleTaskStackSize=configMINIMAL_STACK_SIZE; } -
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer, StackType_t ** ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize ) { * ppxTimerTaskTCBBuffer=&timer_task_tcb; * ppxTimerTaskStackBuffer=timner_task_stack; * pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH; }
-
-
定义函数入口参数
#define START_TASK_PRIO 1 /* 任务优先级 */ #define START_STK_SIZE 128 /* 任务堆栈大小 */ TaskHandle_t StartTask_Handler; /* 任务句柄 */ StackType_t start_task_stack[START_STK_SIZE]; StaticTask_t start_task_tcb; void start_task(void *pvParameters); /* 任务函数 */ -
编写任务函数
StartTask_Handler=xTaskCreateStatic( (TaskFunction_t) start_task, (char * ) "start_task", (uint32_t) START_STK_SIZE, (void * ) NULL, (UBaseType_t) START_TASK_PRIO, (StackType_t * ) start_task_stack, (StaticTask_t * ) &start_task_tcb );
相较于动态创建任务
多了 一个空闲任务内存分配函数和定时器内存分配函数
创建命令 多了两个入口函数
附静态创建任务代码
/*FreeRTOS配置*/
/* START_TASK 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define START_TASK_PRIO 1 /* 任务优先级 */
#define START_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t StartTask_Handler; /* 任务句柄 */
StackType_t start_task_stack[START_STK_SIZE];
StaticTask_t start_task_tcb;
void start_task(void *pvParameters); /* 任务函数 */
/* TASK1 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK1_PRIO 2 /* 任务优先级 */
#define TASK1_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t TASK1_Handler; /* 任务句柄 */
StackType_t task1_stack[START_STK_SIZE];
StaticTask_t task1_tcb;
void TASK1(void *pvParameters); /* 任务函数 */
/* TASK2 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK2_PRIO 3 /* 任务优先级 */
#define TASK2_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t TASK2_Handler; /* 任务句柄 */
StackType_t task2_stack[START_STK_SIZE];
StaticTask_t task2_tcb;
void TASK2(void *pvParameters); /* 任务函数 */
/* TASK3 任务 配置
* 包括: 任务句柄 任务优先级 堆栈大小 创建任务
*/
#define TASK3_PRIO 4 /* 任务优先级 */
#define TASK3_STK_SIZE 128 /* 任务堆栈大小 */
TaskHandle_t TASK3_Handler; /* 任务句柄 */
StackType_t task3_stack[START_STK_SIZE];
StaticTask_t task3_tcb;
void TASK3(void *pvParameters); /* 任务函数 */
/******************************************************************************************************/
/*空闲任务配置*/
StaticTask_t idle_task_tcb;
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];
/*定时器任务配置*/
StaticTask_t timer_task_tcb;
StackType_t timner_task_stack[configTIMER_TASK_STACK_DEPTH];
/*空闲任务内存分配*/
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t *pulIdleTaskStackSize )
{
* ppxIdleTaskTCBBuffer=&idle_task_tcb;
* ppxIdleTaskStackBuffer=idle_task_stack;
* pulIdleTaskStackSize=configMINIMAL_STACK_SIZE;
}
/*定时器任务内存分配*/
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
uint32_t *pulTimerTaskStackSize )
{
* ppxTimerTaskTCBBuffer=&timer_task_tcb;
* ppxTimerTaskStackBuffer=timner_task_stack;
*pulTimerTaskStackSize=configTIMER_TASK_STACK_DEPTH;
}
void start_task(void *pvParameters)
{
taskENTER_CRITICAL();
TASK1_Handler = xTaskCreateStatic( (TaskFunction_t )TASK1, /* 任务函数 */
(char* )"TASK1", /* 任务名称 */
(uint16_t )TASK1_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK1_PRIO, /* 任务优先级 */
(StackType_t * ) task1_stack,
(StaticTask_t * ) &task1_tcb );
TASK2_Handler = xTaskCreateStatic((TaskFunction_t )TASK2, /* 任务函数 */
(char* )"TASK2", /* 任务名称 */
(uint16_t )TASK2_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK2_PRIO, /* 任务优先级 */
(StackType_t * ) task2_stack,
(StaticTask_t * ) &task2_tcb );
TASK3_Handler = xTaskCreateStatic( (TaskFunction_t )TASK3, /* 任务函数 */
(char* )"TASK3", /* 任务名称 */
(uint16_t )TASK3_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK3_PRIO, /* 任务优先级 */
(StackType_t * ) task3_stack,
(StaticTask_t * ) &task3_tcb );
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
void TASK1(void *pvParameters)
{
while(1)
{
printf("task1 ruing!!!\n");
LED0_TOGGLE();
vTaskDelay(500);
}
}
void TASK2(void *pvParameters)
{
while(1)
{
printf("task2 ruing!!!\n");
LED1_TOGGLE();
vTaskDelay(1000);
}
}
void TASK3(void *pvParameters)
{
uint8_t key=0;
while(1)
{
printf("task3 ruing!!!\n");
key=key_scan(0);
if(key==KEY0_PRES)
{
if(TASK1_Handler!=NULL)
{
printf("delete task1 \n");
vTaskDelete(TASK1_Handler);
TASK1_Handler = NULL;
}
}
vTaskDelay(50);
}
}