嵌入式系统(或俗称“单片机系统”)有以下几个概念:
1)死循环
嵌入式系统是连续不断运行的,所以必然有一个“死循环”,一般用以下程序实现:
While(1)
{
……
}
2)标志驱动
对于嵌入式系统,小的应用一般没有操作系统,内存不够,开销也大,所以需要自己设置一些标志,以实现类似于PC上的“消息驱动”。
在上述循环中,程序顺序检测各个标志,根据标志做相应的处理。标志的建立一般由中断完成,或者是中断处理后产生。
3)时基
多数程序都有按时间处理的需求,如延时、定时查询、周期测量等等,所以一定有一个时基,由定时器中断产生,建立标志。在PC中也有类似的机制,DOS时代的PC我知道系统有一个18.2ms的时钟信号,现在的PC不太清楚了 : (
我设计系统通常使用1ms时基,因为多数处理不会小于这个间隔。由此,要设计一个1ms中断标志。所有与时间相关的处理都安排在1ms中断标志建立后的处理中。
4)状态
一个功能的实现,往往不能“一蹴而就”。
就拿超声波测距来说:首先得发出超声波,之后等待回波,等待过程中要根据时间控制增益,逐渐增大,以弥补声波随距离增加的衰减。收到后再计算,至此才能得到一个测量结果。
按照声波速度,2m距离约需要12ms(来回4m)。如果程序设计成顺序依次处理模式,直到完成后再处理其它的任务,则大概通讯成功率只有一半了,因为MCU的处理给测距过程独占了。
也许有人说:可以用中断来处理。
在此,顺便说一下:在成熟的程序中,中断处理中尽量少安排操作。因为一是会由于中断内、外同时处理相同变量产生错误,除非你设计了严格的“闭锁”机制;二是降低了其它中断的响应速度,也许会导致程序性能下降;如需要精确捕捉脉冲,则会由于延时响应而降低精度。优先级机制虽可弥补,但那更容易导致数据错误,而且需要更多的堆栈空间。
为了避免上述问题,通常使用状态来标注一个功能做到了哪一步?设置一个状态变量,记录功能实现的进程,每次轮回时根据状态做相应的事,把能做的做完后立刻退出,把MCU的处理能力交给别的任务。
这就是“分时”处理的概念,只不过分时是由自己写的程序所调度,而非“操作系统”,随着所做的项目复杂度加大,你会感到“操作系统”的重要!
而利用状态控制大概就是所谓的“有限状态机”,这在嵌入式系统中是常见的。
具体实施时,采用螺旋式步骤完成程序。
先构建一个最基本的程序框架:(这一步在VC中,建立MFC工程时就自动完成了,可在单片机上,得自己为之 )

图 1 程序主框架
(使用图片表示并非想阻碍拷贝,只是想借用编辑器的彩色表示方式,更直观,下同)
从上图可以看出,程序基本上由初始化和死循环组成,死循环中设计了三个处理:时基、通讯、测量(工作),这三件事因为需要同时处理,所以设计在循环中依次得到MCU的处理时间。读者可回忆一下流程图格式,有了这个还需要吗?
然后逐步充实,每构思一个功能:
1) 定义相关变量
2) 在init_var()中初始化;
3) 根据需要定义相关常数;
4) 涉及硬件,在init_hardware()中初始化硬件;
5) 构建处理方法,也就是函数,完成功能;
6) 如完成需要等待外部条件,则定义状态变量,并定义状态,转换条件;
7) 处理时如涉及定时,则设置计时器,建立相应标志,在时基处理中添加处理;
不一定要一个螺旋就上到“顶”,可以逐步添加,首先是实现功能必备的处理,其次是防护出错的保护性处理。程序将逐步变得完善、可靠。最终得到的程序自然比较复杂,而读程序者通常看到的是这个版本,所以自然费解!
读者如果接触过编程,一定知道“面向对象”,这个概念开始时我很不理解,汇编程序写多了,思维更“接近”机器。在编写几次VC程序后,觉得“面向对象”倒是一个不错的思维方式,即从你要做的事情开始思考,它要完成什么?它有什么特征?它怎么去做?可以类比一下,上述功能定义说明了它要完成什么?变量定义说明了特征,而处理方法指明它如何去做。也许不太贴切,但是自我感觉有不小的帮助。
本开源项目地址:

【