目录
-
单任务与多任务
单片机裸机编程的时候,都会用一个while(1)去包裹所有应用程序,换言之,裸机编程中的应用程序就运行在一个死循环while(1)中,而且各个应用程序都是排队轮流执行的(中断除外),只要前面的程序没有完成,后面的程序就必须等待。
这种裸机编程非常容易实现,对于顺序执行的逻辑可以控制得很好,但是当外部资源庞大,程序逻辑复杂,需要突然程序跳转的设置,某些应用程序会在某个不可预测的时间上需要实时性执行,此时裸机编程就无能为力了,裸机编程的系统一般称为单任务系统,显然现在需要多任务系统。
多任务系统假若在单核版上运行,那么意味着每个时刻只有一个任务在进行,下一个时刻到底选择哪个任务去执行?需要一个掌控全局任务执行时间安排的角色:调度器。调度器的基本功能是使得任务可以切出和切入,在某个任务需要马上执行的时候立刻打断当前正在执行的任务,这样就使得系统具有实时性。调度器的存在也使得任务具有多种特性,比如优先级、堆栈空间等等。
-
任务优先级
调度器选择任务执行的依据是任务的优先级,FreeRTOS的任务优先级是0~(configMAX_PRIORITIES-1),configMAX_PRIORITIES在FreeRTOSConfig.h(可以看上一文)中定义,0是最低优先级,数值越大优先级越高。
调度器选择任务需要有一个调度算法,调度器总是选择优先级最高的任务去执行,如果任务队伍中的优先级一样,就采用时间片的方法法轮流执行,每个任务执行一段时间,随后切换同级的其它任务。
-
任务控制块
-
任务堆栈
-
任务创建与删除
任务创建与删除的API函数:
总体流程如图:
创建与删除:
任务函数需要绑定在任务中才能被执行,而任务需要创建,FreeRTOS提供任务相关的API,创建任务的API有3种,常用的是xTaskCreate(),不同的API用途在上表查看,xTaskCreate()的原型及需要的头文件如下:
任务函数运行在死循环之内,不能以任何方式返回,如果任务函数实在不需要继续执行,那么可以使用vTaskDelete()API函数主动或者被动删除任务。任务删除后就不再运行,变成了“僵尸”,等待着内核收尸。vTaskDelete()的原型及需要的头文件如下:
//开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建TASK1任务
xTaskCreate((TaskFunction_t )task1_task,
(const char* )"task1_task",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
//创建TASK2任务
xTaskCreate((TaskFunction_t )task2_task,
(const char* )"task2_task",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_TASK_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//创建开始任务
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(); //开启任务调度
Tist:
- 相对于多任务系统,单任务系统不能处理实时性的任务需要
- 多任务切换需要调度器的存在
- 任务具有任务函数,优先级,堆栈空间的特性