引言
嵌入式系统通常由嵌入式处理器、外围设备、嵌入式软件等部分组成,其中微处理器(MCU)在嵌入式系统中占据着相当重要的位置。由于MCU大多是8位或16位机,内部资源和运算能力都受到限制,无法与高性能处理器相比较,不能运用比较成熟的嵌入式实时操作系统,系统软件又与硬件平台有较大关联,故而需要开发人员自己进行软件体系的构建[1]。嵌入式系统对于实时性要求很高,如何处理各个任务的运行和调度,也会直接影响到嵌入式系统的可靠性乃至整体性能。因此好的软件体系架构,对开发优秀而可靠的嵌入式应用系统极其重要。
1 系统概述与问题提出
天津大学流量实验室研发了一款测量精度高、系统功耗低、功能完善、可靠性高的数字涡街流量计。考虑到低功耗和实时响应是流量计设计的重点,在设计中选用了MSP430F1611单片机为控制器。基于单片机的数字涡街流量计,往往由于工作频率低而导致系统实时性比较差(优化前系统的执行周期时间是2.5 s)。由于温度、压力的变化容易对气体密度造成明显的影响,因此在测量质量流量时进行了密度补偿。同时针对水蒸汽密度测量困难的问题,采用基于IAPWSIF97公式的密度补偿方案[2]。
在原有设计中,硬件电路和外围器件布局的设计是比较合理的,但是系统软件部分的设计差强人意。主要表现为:程序没有对功能模块和层次进行细致的划分,主程序中含有大量与硬件平台相关的代码,不利于阅读和修改维护;按键与LCD显示存在明显延迟,极端情况下甚至会出现按键无响应的情况。以上这些说明该系统软件在实时性和可靠性方面都存在缺陷,即软件体系架构在一定程度上是不合理的。图1为未进行优化前的系统软件体系结构。可以看出,每隔2.5 s整个系统会循环执行一次。这种结构的缺点在于:①按键和屏幕显示不能获得及时的响应;②按键处理过程中使用软件延时消除抖动,会降低系统的实时性;③串口通信结束后,系统长时间处于等待状态,无法及时处理其他任务。本文在优化该数字涡街流量计的原有软件架构的同时,给出了如何设计出合理的嵌入式软件体系的方法,系统的实时性和可靠性得到了改进。
图1 原始程序流程图
2 软件架构与设计
嵌入式系统设计中普遍使用16位MCU,而这些MCU的功能和资源都非常有限,运行嵌入式实时操作系统往往存在很大的负担,因此要自行设计该嵌入式系统的软件体系结构。这里引入了程序模块化的思想。模块化是软件架构和程序设计重要的方法和手段。在模块化的程序结构中,主程序仅仅是执行调度功能,负责及时调用功能模块程序。
2.1 程序模块化
C语言作为一种结构化的程序设计语言,主要依据程序的功能进行模块划分[7]。
程序设计的过程中,将各个功能模块的程序都放到一个.c文件中,同时在.h文件中进行模块接口的声明,以方便其他文件的调用和管理。对于底层与硬件设备紧密相关的代码用精炼的语言编写,执行效率高。其他与硬件平台无关的代码运用模块化编程思想编写,以便于代码的移植与重用。按照这种思想,改进后的数字涡街流量计的程序划分为如下几个模块:按键处理模块、LCD显示模块、温压补偿模块、脉冲捕获方法测频率模块、FFT方法测频率模块、通信模块、脉冲输出/PWM波输出模块等[6]。
2.2 系统任务调度机制
嵌入式系统要获得很高的实时性和可靠性,就要有合理的软件架构。基于MCU的嵌入式系统程序典型执行顺序为:首先对硬件设备进行初始化;然后对软件模块进行初始化;最后程序进入无限循环,继续调用模块的处理函数。首选的循环实现方案是while(1){}。
在while(1){}模式中,通过使用事件驱动机制和前后台程序结构来对各个模块进行调度。事件驱动机制的原理就是给每个功能模块设置变量作为“使能标志”,通过使能该标志来触发模块所代表的事件。而前后台程序结构是由主循环加中断构成的。在while(1){}循环体系中,主程序按照顺序来查询各个模块的使能标志变量,当发现标志被使能时则执行相应任务,否则放弃。在这种方式下常见的有如下两种调度机制。
(1) 顺序调度机制
顺序调度机制示意图如图2所示。
图2 顺序调度机制示意图
在这种调度机制情况下,各功能模块在主程序中没有优先级的区别,主程序会依次轮询各个模块的使能标志变量,通过判断该使能标志的情况,进行模块调度的决定。
顺序调度机制的程序结构优点是,这一模式可以保证所有的功能模块得到同等的调度的机会。但是它的缺点也很明显:可能不能及时响应对于实时性要求较高的任务。
(2) 优先调度机制
图3为优先调度机制的示意图。优先调度机制的特点是主程序按照一定的优先级次序,查询各个功能模块的使能标志变量。在完成模块任务后跳出本次循环,开始新一轮的查询和执行。
图3 优先调度机制示意图
优先调度机制的程序结构的优点在于,这一模式可以让排在前面的优先级较高的功能模块获得及时迅速的响应。
未修改前的系统软件程序使用顺序调度机制,轮询调度的周期是2.5 s,这样能够确保每个模块都能够被同等调用,但对于某些实时性要求较高的功能模块得不到及时响应。而优化改进后的程序使用优先调度机制,能够使具有较高实时性的模块靠前调用。对于突发事件的及时响应,可以使用设置中断方式,例如按键响应等任务都采用中断方式进行响应。得到的修改后的主程序图如图4所示。
图4 优化后的程序流程图
2.3 具体程序的模块化
在程序的设计中,除了按功能划分的模块之外,通常还包括两类基本的模块:硬件驱动模块和软件驱动模块。同时,软件功能模块要满足低耦合和高内聚的要求。
2.3.1 硬件驱动模块
硬件驱动模块一般包括函数有:硬件设备初始化、设置CPU为对应硬件的控制线、对外围设备提供操作接口函数。
直接作用于硬件的驱动程序应该放到单独的模块中,同时封装成具有标准接口的API函数。例如LCD液晶显示的控制,应当把写数据、写命令、显示字符等函数封装成API函数,以方便调用,使调用函数不必再对硬件寄存器直接进行操作。也可以将针对外围设备的底层操作做成程序驱动库,相当于各个外设的API函数,这样方便上层程序的调用和管理[6]。
2.3.2 软件功能模块
软件模块的程序设计中,选择简洁合理的算法是非常重要的。例如FFT算法具有高复杂性,对处理器的运算速度和RAM大小都有一定要求,所以FFT算法及采样点个数的选择对于提高软件系统实时性非常重要。
FFT算法有基2、基4、以及分裂基FFT算法和MFFT算法,考虑到MCU的性能和C语言实现的复杂度,选择了基2的FFT算法。基2的FFT算法的主要步骤是同时将两个数从内存中取出逆序排列,运行蝶形运算,将结果放回到内存中去。设计中对采样的1 024个点进行FFT运算,如果直接进行DFT复数乘法,次数为1 048 576次,而FFT算法只需要5 120次,大幅度降低了运算量,节省了计算时间。这种实现方法占用RAM较小,运算次数也较少。同时为提高运算速度,运行FFT算法前打开4 MHz时钟,FFT算法完成后关闭4 MHz时钟,打开DCO降低系统功耗[5]。
2.3.3 中断服务程序
中断的设置也是嵌入式系统实时性的重要手段。在实际应用中,主程序通过标志变量的值来判断发生的中断并调用对应的中断处理程序。在优化后的程序中对按键的处理设置为中断方式,一旦有按键按下,CPU进行响应,将按键中断标志位置1,退出中断,主程序调用按键功能模块。这样缩短了中断执行时间,以便能够响应其他中断,提高了系统的实时性。同样在温度和压力的采样过程中也运用中断方式进行响应,中断服务子程序只进行数据存储,在主函数中才对数据进行处理[5]。
3 实验验证
针对优化改进前后的软件体系架构的实时性,设计了对比实验。按键后液晶屏幕显示切换,屏幕的及时响应就能够反应系统的实时性。通过使用秒表记录数字涡街流量计的屏幕切换的时间,来对优化前后的软件体系结构的实时性进行对比。实验的具体过程是给该数字涡街流量计上电,然后通过按键进行画面的调节,多次验证,得到软件优化前后的屏幕切换时间。实验的屏幕画面切换过程如图5所示。测得的系统软件优化前后屏幕切换时间如表1所列。实验结果表明:在多次的重复实验中,优化后的系统软件在实时性方面表现较好。
图5 屏幕切换画面
表1 实验测量结果
结语
嵌入式系统要求有很高的实时性和可靠性,只有构建出好的软件体系才能保证嵌入式系统的稳定运行。通过对原有嵌入式系统中软件的重新设计,给出了如何构建适用于自身系统的、具有较高的鲁棒性和实时性的软件体系的一般方法。通过对比,修改后的系统改善了按键与显示的延迟问题,人机交互方面的实时性有很大提高。程序框架也更加简明和有条理,方便以后的阅读、修改和移植。实验结果表明,在实现基本功能的基础上,优化后的嵌入式系统软件确实拥有更好的实时性和可靠性。