文章目录
- 一、FreeRTOS任务特性
- 二、FreeRTOS任务状态
- 三、FreeRTOS任务优先级
- 四、FreeRTOS任务实现
- 五、任务控制块
- 六、任务堆栈
一、FreeRTOS任务特性
- 简单
- 没有使用限制(任务数量没有显示,一个优先级下可以有多个任务)
- 支持抢占(高优先级任务可以抢占低优先级任务的CPU使用权)
- 支持优先级
- 每个任务都拥有堆栈,导致RAM使用量增大
当任务切换时,需要保护现场,保证再次执行该任务时能够从中断的地方继续执行,现场就存储在任务的RAM中。 - 如果使用抢占,需要考虑重入问题
二、FreeRTOS任务状态
- 运行态
任务正在执行时,处于运行态 - 就绪态
任务准备就绪,可以运行 - 阻塞态
比如某个任务在等待某一个事件发生,此时任务处于阻塞态 - 挂起态
挂起态就是任务暂停运行
这四种任务状态是可以互相转换的。任务创建完成之后,处于就绪态。如果任务调度器调度了处于就绪态的任务,此时任务状态变成了就绪态。当然,运行态也可以编程就绪态。比如此时A任务正在运行,此时有一个比A任务优先级高的B任务处于就绪态。这是任务调度器会将A任务的CPU使用权转交给B任务,此时A任务从运行态转入就绪态。
由就绪态到挂起态,可以直接通过函数vTaskSuspend()实现。运行态和阻塞态也可以调用函数vTaskSuspend(),进入挂起态。解挂时,调用vTaskResume()函数即可。
如果处于运行态的任务调用了一些可以阻塞的API函数,比如等待状态量,等待消息队列等,处于运行态的任务就会转到阻塞态。
三、FreeRTOS任务优先级
任务优先级高的任务,会先被执行。在FreeRTOS周末和,任务优先级可选范围在0~configMAX_PRIORITIER - 1,同一优先级下,可以有多个任务。值得注意的是,在FreeRTOS中,数字越大,优先级越大。
四、FreeRTOS任务实现
FreeRTOS官方给出了一个任务函数的模板
void vATaskFunction(void *pvParameters)
{
for( ; ; ) // 死循环,可以用while(1)
{
// 任务应用程序
vTaskDelay(); // 引起任务调度
}
}
一般情况下,我们不会从任务中跳出。如果需要调出,一定要将任务删除。删除任务可以调用下面的函数
vTaskDelete(NULL); // 删除任务
需要注意的是,FreeRTOS的任务函数必须是void类型。
五、任务控制块
FreeRTOS 把任务属性集合到一起,用一个结构体来表示,这个结构体就是任务控制块——TCB_t(Task Control Block)。所以总结来说,任务控制块就是描述任务属性的结构体。任务控制块可以在“task.c”文件中找到。
六、任务堆栈
上面介绍过,当正在执行任务A,需要切换到任务B时,会将当前任务的现场(CPU寄存器值等)保存到人物的任务堆栈中。等到任务A再次运行时,根据从任务A的任务堆栈中存储的值来恢复现场。
创建任务的时候需要给任务指定堆栈。如果使用的函数 xTaskCreate()创建任务(动态创建),任务堆栈就会由函数 xTaskCreate()自动创建。如果使用函数 xTaskCreateStatic()创建任务(静态方法),需要程序员自行定义任务堆栈。然后堆栈首地址作为函数的参数 puxStackBuffer 传递给函数。
不管是使用函数xTaskCreatel()还是xTaskCreateStatic0创建任务,都需要指定任务堆栈大小。任务堆栈的数据类型为 StackType_t, Stackype_t 本质上是 uint32 t,在 portmacro.h 中有定义
#define portSTACK_TYPE uint32_t
typedef portSTACK_TYPE StackType_t;
由此可见,任务堆栈StackType_t的变量类型是u32,无符号整型。
比如之前在移植测试程序中创建LED程序时,定义任务堆栈
//任务堆栈大小
#define LED0_STK_SIZE 50
这里的“50”并不是指该任务的任务堆栈大小为50个字节。而是指该任务的任务堆栈大小是50个StackType_t。一个StackType_t是四个字节。因此,该任务的任务堆栈大小应该是4 * 50 = 200 字节。
任务堆栈需要根据任务的实际大小分配,如果任务所需要的内存比较大,需要调整任务堆栈大小。如果出现任务卡死不运行的情况,大多数情况是因为任务堆栈分配太小。
但是如果任务卡住,将其堆栈增大到很大,依旧卡住,那应该是其他问题。