FreeRTOS笔记(一)
文章目录
裸机系统与多任务系统
裸机系统
裸机系统通常分成轮询系统和前后台系统。
轮询系统
轮询系统即是在裸机编程的时候,先初始化好相关的硬件,然后让主程序在一个死循环里面不断循环,顺序地做各种事情。
轮询系统是一种非常简单的软件结构,通常只适用于那些只需要顺序执行代码且不需要外部事件来驱动的就能完成的事情。
如果加入了按键操作等需要检测外部信号的事件用来模拟紧急报警,那么整个系统的实时响应能力并不会那么好。
示例 1
int main(void)
{
/* 硬件相关初始化 */
HardWareInit();
/* 无限循环 */
for (;;) {
/* 处理事情 1 */
DoSomething1();
/* 处理事情 2 */
DoSomething2();
/* 处理事情 3 */
DoSomething3();
}
}
前后台系统
相比轮询系统,前后台系统是在轮询系统的基础上加入了中断。外部事件的响应在中断里面完成,事件的处理还是回到轮询系统中完成,中断在这里称为前台, main 函数里面的无限循环称为后台。
在顺序执行后台程序的时候,如果有中断来临,那么中断会打断后台程序的正常执行流,转而去执行中断服务程序,在中断服务程序里面标记事件,如果事件要处理的事情很简短,则可在中断服务程序里面处理,如果事件要处理的事情比较多,则返回到后台程序里面处理。
前后台系统确保了事件不会丢失,再加上中断具有可嵌套的功能,这可以大大的提高程序的实时响应能力。在大多数的中小型项目中,前后台系统运用的好,堪称有操作系统的效果。
示例 2
int flag1 = 0;
int flag2 = 0;
int flag3 = 0;
int main(void)
{
/* 硬件相关初始化 */
HardWareInit();
/* 无限循环 */
for (;;) {
if (flag1) {
/* 处理事情 1 */
DoSomething1();
}
if (flag2) {
/* 处理事情 2 */
DoSomething2();
}
if (flag3) {
/* 处理事情 3 */
DoSomething3();
}
}
}
void ISR1(void)
{
/* 置位标志位 */
flag1 = 1;
/* 如果事件处理时间很短,则在中断里面处理
如果事件处理时间比较长,在回到前台处理 */
DoSomething1();
}
void ISR2(void)
{
/* 置位标志位 */
flag2 = 1;
/* 如果事件处理时间很短,则在中断里面处理
如果事件处理时间比较长,在回到前台处理 */
DoSomething2();
}
void ISR3(void)
{
/* 置位标志位 */
flag3 = 1;
/* 如果事件处理时间很短,则在中断里面处理
如果事件处理时间比较长,在回到前台处理 */
DoSomething3();
}
多任务系统
相比前后台系统,多任务系统的事件响应也是在中断中完成的,但是事件的处理是在任务中完成的。
在多任务系统中, 任务跟中断一样,也具有优先级,优先级高的任务会被优先执行。当一个紧急的事件在中断被标记之后,如果事件对应的任务的优先级足够高,就会立马得到响应。
相比前后台系统,多任务系统的实时性又被提高了。
示例 3
int flag1 = 0;
int flag2 = 0;
int flag3 = 0;
int main(void)
{
/* 硬件相关初始化 */
HardWareInit();
/* OS 初始化 */
RTOSInit();
/* OS 启动,开始多任务调度,不再返回 */
RTOSStart();
}
void ISR1(void)
{
/* 置位标志位 */
flag1 = 1;
}
void ISR2(void)
{
/* 置位标志位 */
flag2 = 2;
}
void ISR3(void)
{
/* 置位标志位 */
flag3 = 1;
}
void DoSomething1(void)
{
/* 无限循环,不能返回 */
for (;;) {
/* 任务实体 */
if (flag1) {
}
}
}
void DoSomething2(void)
{
/* 无限循环,不能返回 */
for (;;) {
/* 任务实体 */
if (flag2) {
}
}
}
void DoSomething3(void)
{
/* 无限循环,不能返回 */
for (;;) {
/* 任务实体 */
if (flag3) {
}
}
}
相比前后台系统中后台顺序执行的程序主体,在多任务系统中,根据程序的功能,我们把这个程序主体分割成一个个独立的,无限循环且不能返回的小程序,这个小程序我们称之为任务。
每个任务都是独立的,互不干扰的,且具备自身的优先级,它由操作系统调度管理。加入操作系统后,我们在编程的时候不需要精心地去设计程序的执行流,不用担心每个功能模块之间是否存在干扰。
整个系统随之带来的额外开销就是操作系统占据的那一丁点的 FLASH 和 RAM。现如今,单片机的 FLASH 和 RAM 是越来越大,完全足以抵挡 RTOS 那点开销。
表 1 轮询、前后台和多任务系统软件模型区别
模型 | 事件响应 | 事件处理 | 特点 |
---|---|---|---|
轮询系统 | 主程序 | 主程序 | 轮询响应事件,轮询处理事件 |
前后台系统 | 中断 | 主程序 | 实时响应事件,轮询处理事件 |
多任务系统 | 中断 | 任务 | 实时响应事件,实时处理事件 |
列表和列表项(list & list item)
列表和列表项对应 C 语言当中的链表和节点。
链表分为单向链表和双向链表,单向链表很少用,使用最多的还是双向链表。
单向链表
图 1 单向链表
节点本身必须包含一个节点指针,用于指向后一个节点,除了这个节点指针是必须有的之外,节点本身还可以携带一些私有信息如单个的数据、数组、指针数据和自定义的结构体数据类型等等信息,因此常用结构体来表示节点,见示例 4。
示例 4 节点结构体定义
struct node
{
struct node *next; /* 指向链表的下一个节点 */
char data1; /* 单个的数据 */
unsigned char array[];