谈单片机软件架构

#Technomous

单片机裸机系统通常分为轮询系统和前后台系统。下面我们分别来看看这两种系统。

轮询系统

轮询系统就是在裸机编程的时候,先初始化好相关的硬件,然后让主程序在一个死循环里不断循环,顺序的做各种事情。轮询系统是一种非常简单的软件结构,通常适用于那些只需要顺序执行代码且不需要外部事件来驱动就能完成的事情。比如,如果只是实现 LED 翻转,串口输出,液晶显示等这些操作,那么使用轮询系统将会非常完美。但是,如果加入了按键操作等需要检测外部信号的事件,用来模拟紧急报警,那么整个系统的实时响应能力就不会那么好了。比如假设 DoSomething3 是处理按键扫描事件。当外部按键被按下,需要立马响应并做紧急处理,而这个时候程序刚好执行到 DoSomething1,要命的是 DoSomething1 需要执行的时间比较久,久到按键释放之后都没有执行完毕,那么当执行到 DoSomething3 的时候就会丢掉一次事件。足见,轮询系统只适合顺序执行的功能代码,当有外部事件驱动时,实时性就会降低。

int main(void)
{
    /* 硬件相关初始化 */
    HardWareInit();

    /* 无限循环 */
    for (;;)
    {
        DoSomething1();
        DoSomething2();
        DoSomething3();
    }
}

前后台系统

相比于轮询系统,前后台系统是在轮询系统的基础上加入了中断。外部事件的响应在中断里面完成,事件的处理还是回到轮询系统中完成,中断在这里我们称为前台,main 函数里面的无限循环我们称为后台。

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();
}

在顺序执行后台程序的时候,如果有中断来临,那么中断会打断后台程序的正常执行流,转而去执行中断服务程序,在中断服务程序里面标记事件,如果事件要处理的事情很简短,则可在中断服务程序里面处理,如果事件要处理的事情比较多,则返回到后台程序里面处理。虽然事件的响应和处理是分开了,但是事件的处理还是在后台里面顺序执行的,但相比轮询系统,前后台系统确保了事件不会丢失,再加上中断具有可嵌套的功能,这可以大大的提高程序的实时响应能力。在大多数的中小项目中,前后台系统运用的好,堪称有操作系统的效果。

多任务系统

如果在此基础上拓展一下,将事件的处理放在任务中完成,并且任务也跟中断一样,也具有优先级,优先级高的任务会被优先执行,这样就会得到一个多任务处理系统。当一个紧急的事件在中断中被标记之后,如果事件对应的优先级足够高,就会立马得到响应。相比于前后台系统,多任务系统的实时性又被提高了。

模型 事件响应 事件处理 特点
轮询系统 主程序 主程序 轮询响应时间,轮询处理事件
前后台系统 中断 主程序 实时响应事件,轮询处理事件
多任务系统 中断 任务 实时响应事件,实时处理事件

通过以上论述,可以大致总结出三种系统的特点。