0 概述
部分内容参考野火的FreeRTOS相关开发资料,在此做一个学习记录总结。
1 裸机系统与多任务系统
1.1 裸机系统
做51单片机开发的人比较熟悉,在实现LED流水灯时,使用while(1)配合简单延时函数,循环配置引脚寄存器输出高低电平实现灯的亮灭,这个就是属于最常见裸机系统。
裸机系统通常分为轮训系统和前后台系统。
- 轮询系统
上面的LED翻转的例子就是轮训系统,一般适用于只需要顺序执行代码,且不需要关心外部事件驱动,如按键检测等。
伪代码如下:
int main(void)
{
/* 硬件相关初始化 */
HardWareInit();
/* 无限循环 */
for (;;) {
/* 处理事情 1 */
DoSomething1();
/* 处理事情 2 */
DoSomething2();
/* 处理事情 3 */
DoSomething3();
}
}
轮询系统有什么缺点呢?
假设事件3中需要处理一个按键检测的动作,但是按键按下去的时候,正在执行任务1,并且任务1很耗时,这样按键检测的动作就被遗漏了。
并且,如果每个事件都需要及时被处理,但是存在个别事件的处理是耗时的,那么其他事件就只能等待,造成事件处理延时。
- 前后台系统
我们将mian函数里面的循环称为后台,中断称之为前台。
在轮询系统的基础上引入中断机制,外部时间的响应在中断里面完成,如果时间处理不耗时,则可以在中断里面直接处理,否则要将事件的处理放到轮训系统中,一般建议将事件的处理放到后台任务处理。
伪代码如下:
int flag1 = 0;
int flag2 = 0;
int flag3 = 0;
int main(void)
{
/* 硬件相关初始化 */
HardWareInit();
/* 无限循环 */
for (;;) {
if (flag1) {
/* 处理事情 */
DoSomething1();
}
if (flag2) {
/* 处理事情 */
DoSomething2();
}
if (flag3) {
/* 处理事情 */
DoSomething3();
}
}
}
void ISR1(void)
{
/* 置位标志位 *
flag1 = 1;
/* 如果事件处理时间很短,则在中断里面处理
如果事件处理时间比较长,在回到前台处理
*/
DoSomething1();
}
void ISR2(void)
{
/* 置位标志位 */
flag2 = 1;
/* 如果事件处理时间很短,则在中断里面处理
如果事件处理时间比较长,在回到前台处理
*/
DoSomething2();
}
void ISR3(void)
{
/* 置位标志位 */
flag3 = 1;
/* 如果事件处理时间很短,则在中断里面处理
如果事件处理时间比较长,在回到前台处理
*/
DoSomething3();
}
相对轮询系统,前后台系统有什么优势呢?
将事件的响应和处理分开了,虽然事件的处理还是在后台程序中,但是前后台系统确保了事件不会丢失,加上中断可以嵌套,因此大大提高了程序的实时响应能力。
在大多数中小型项目中,前后台系统运用的很好。
1.2 多任务系统
多任务系统的时间响应也是在中断中完成,但是事件的处理是在任务中完成,可以认为是和main类似的后台任务模块。
那么什么是任务呢?
我们把程序主体分割成一个个独立的、无限循环、不能返回的小程序,这样的小程序我们称为任务。
应用中为满足不同的需求,会存在多个任务,与前后台系统的后台main处理不同。多任务系统的每个任务和中断一样,也具有优先级,优先级高的任务会被优先执行。当一个紧急的事件在中断被标记后,如果事件的优先级足够高,就会得到立马响应,获取CPU控制权。相比前后台系统,多任务系统的实时性又被提高了,不需要等待其他事假处理完毕才能对自身事件进行处理。
具体的任务调度是由操作系统进行调度管理。
加入多任务系统之后,我们编程的时候就不需要太过于精心的设计程序执行流程,以及担忧各个模块之间的干扰,编程的重点转移到业务实现上,总的来说,编程变得简单了。
1.3 小结
轮询、前后台、多任务系统均有其使用场景,不能一句话判定孰优孰劣。
三种软件系统的区别如下:
模型 | 事件响应 | 时间处理 | 特点 |
---|---|---|---|
轮询系统 | main主程序 | main主程序 | 轮询响应事件,轮询处理事件 |
前后台系统 | 中断 | main主程序 | 中断响应事件,轮询处理事件 |
多任务系统 | 中断 | 任务 | 实时响应事件,实时处理事件 |