早期的嵌入式系统中没有操作系统的概念,程序员编写嵌入式程序通常直接面对裸机及裸设备。在这种情况下,通常把嵌入式程序分成两部分,即前台程序和后台程序。
应用程序是一个无限的循环,循环中调用相应的函数完成相应的操作,这部分可以看成后台行为。前台程序通过中断来处理事件;后台程序则掌管整个嵌入式系统软、硬件资源的分配、管理以及任务的调度,是一个系统管理调度程序。这就是通常所说的前后台系统。一般情况下,后台程序也叫任务级程序,前台程序也叫事件处理级程序。在程序运行时,后台程序检查每个任务是否具备运行条件,通过一定的调度算法来完成相应的操作。对于实时性要求特别严格的操作通常由中断来完成,仅在中断服务程序中标记事件的发生,不再做任何工作就退出中断,经过后台程序的调度,转由前台程序完成事件的处理,这样就不会造成在中断服务程序中处理费时的事件而影响后续和其他中断。
实际上,前后台系统的实时性比预计的要差。这是因为前后台系统认为所有的任务具有相同的优先级别,即是平等的,而且任务的执行又是通过FIFO队列排队,因而对那些实时性要求高的任务不可能立刻得到处理。另外,由于后台程序是一个无限循环的结构,一旦在这个循环体中正在处理的任务崩溃,使得整个任务队列中的其他任务得不到机会被处理,从而造成整个系统的崩溃。由于这类系统结构简单,几乎不需要RAM/ROM的额外开销,因而在简单的嵌入式应用被广泛使用。
紧急的事务一定要用中断处理!中断只处理紧急事务!
(题外话:对于常数类型,建议使用 enum 分类组织,避免使用大量 #define 定义常数)
前后台系统面临的一个直接困境是,软件规模大了,很难管理。处理的模块一多的话,实时性也根本难以保障. 首先是中断可以在主程序的任何地方发生,随意打断主程序。其次主程序与中断之间的耦合性(关联度)较大,这种做法使得主程序与中断缠绕在一起,必须仔细处理以防不测。
中断驱动多任务--- 单片机(MCU) 下的一种软件设计结构
方法一:利用设定好的时基使用中断来执行任务,不做动态调度。每次进入定时中断时,复位堆栈,不返回中断点。接着,执行用户任务直至结束。结束时,进入死循环,等待中断发生。
#define CountOfArray(x) (sizeof(x)/sizeof(x[0]))
typedef void (*FUNCTIONPTR)();
const FUNCTIONPTR[] tasks = { ProcessKey, RunTask2,…RunTaskN};
void Timer_Interrupt() {
SetTimer();
ResetStack();
Enable_Timer_Interrupt;
for (i=0; i (*tasks[i])(); while (1) IDLE; } 任务的时间片划分方法:状态机 (state machine)(为了保证每个时基内执行相应的任务片) 其它概念: 进程:是一个可以独立调度的任务,是程序的执行过程,动态性,具有生命期。包括:程序段,数据段,进程控制块。 线程:出现在并行处理中,进程里可以独立调度的执行单元,加快进程的执行。 程序:是指令有序的集合,静态性,长久存在ROM上,一个程序可以映射到多个进程。 任务:嵌入式系统中的一个进程,具有休眠态,就绪态,运行态,挂起态,等待态,结束态。 FUNCTIONPTR[COUNTOFTASKS] tasks; tasks[0] = ProcessKey; tasks[0] = RunTaskM; tasks[0] = NULL; ... FUNCTIONPTR pFunc; for (i=0; i< COUNTOFTASKS; i++) { pFunc = tasks[i]); if (pFunc != NULL) (*pFunc)(); } void RunTaskN() { switch (state) { case 0: state0(); break; case 1: state1(); break; … case M: stateM(); break; default: state = 0; } } const FUNCTIONPTR[] states = { state0, state1, …, stateM }; void RunTaskN() { (*states[state])(); } void state0() { } void state1() { state++; } // next state; void state2() { state+=2; } // go to state 4; void state3() { state--; } // go to previous state; void state4() { delay = 100; state++; } void state5() { delay--; if (delay <= 0) state++; } //delay 100*tick