引言
采用嵌入式实时操作系统的益处是,当某一个任务的时间片用完或满足了被挂起的条件时,操作系统将终止该任务的执行,保存现场,切换到其他任务,宏观上看就好像各个任务在同时运行[12]。但正是因为操作系统随时可能将任务打断,这就需要大量的数据空间保存当前的任务状态,加上操作系统本身所占有的大量空间,使得在资源有限的MCU上应用受限。
1 嵌入式手操器概述
本设计中嵌入式手操器基于USB总线,作为主设备用以实现对天津大学流量实验室研发的低功耗数字涡街流量计仪表参数的设置和修改。也可以作为从设备连接到PC机,对手操器中预置参数进行设置,同时满足系统低功耗和使用便捷性的要求。
嵌入式手操器主要模块包括USB接口单元、点阵液晶显示单元、日历/时间/掉电保护单元、电源电量检测单元和全数字按键输入单元。手操器系统硬件结构框图如图1所示。本设计采用低功耗MCU芯片为控制器,外接USB控制芯片实现USB通信。采用18按键的全键盘设计,便于对系统进行控制和菜单选项设置。键盘设计中搭建4×4的矩阵键盘,通过内部软件定时扫描键盘按键是否按下并加以识别,剩下两个按键为开关键和确认键,采用中断方式进行检测。显示部分使用具有32级灰度的160×160点阵式液晶,界面显示中有多级菜单,每屏菜单项还有对应的子菜单(菜单深度最大为5级),并且对43个参数进行修改和显示。同时系统还有电池电量检测以及掉电数据保护功能。
图1 系统硬件整体设计图
2 层次化有限状态机的应用
2.1 有限状态机的数学模型
有限状态机是行为模型,通常将调度应用程序的控制系统进行模块化分成有限个状态,状态机是产生执行信号来代替行为的决策机[3]。
2.2 有限状态机的表示方法
图2所示为一个状态转移图,表示系统设计中的矩阵键盘按键识别的状态迁移关系。一次完整的按键应该包含5个阶段:等待阶段、闭合抖动阶段、有效闭合阶段、释放抖动阶段、有效释放阶段[5]。按键消抖是避免误触发的有效手段,本设计中按键设计摒弃软件延时消抖这种破坏系统实时性的方法,采用定时查询方法。定时器设置产生16 ms的时间片,每隔16 ms进行键盘扫描,如有按键按下或释放用16 ms时间延时消抖。按键识别分成三个状态:等待(确认是否有键按下)、消抖(在等待状态有按键按下,延时16 ms后检查是否任然有效)、释放(等待已确认的按键释放并返回有效键值)。
图2 按键识别状态转移示意图
状态迁移表也可用作描述状态转移,表略——编者注。在系统设计中使用状态迁移图和状态迁移表相结合的方式。既能清楚描述各个状态的详细信息和跳转关系,又能知道跳转的条件以及明确所要执行的动作。
图3为按键识别的流程图,用Key_State变量来表示按键状态的变化。
图3 按键识别程序流程图
2.3 层次化状态机的引入
本设计中有按键识别、对应按键所执行的功能、液晶显示、USB通信、电源检测等功能,划分的状态较多。如果系统有n个状态的话,那就需要维护最多n×n个跳转链接(有限状态机允许自状态跳转),而且对于系统当前处在的状态而言,不能有效地知道其跳转历史,因此这些状态之间的转换就变得复杂甚至是无法控制,此时有必要引入层次化状态机思想[68]。
层次化状态机从某种程度上讲,就是限制了状态机的跳转。每个大状态(外层状态)在内部划分成较细的状态(内部状态),而且状态内的状态是不需要关心外部状态跳转的,这样也做到了无关状态间的隔离,在每个状态的内部只需要关心内部各状态的跳转就可以了。大大降低了状态机的复杂程度,得到一个清晰易懂的状态框架。同时状态机层次化后,可以减少全局变量的使用,层次内的全局变量用static关键字进行定义,限定其作用范围,这样各个层次内的变量变化标志位仅在自己的层次内起作用,设计中存在液晶显示、按键识别、USB通信三个大状态,每个状态中又存在多个子状态,如果没有采用层次化状态机的话,需要多个全局变量来描述全部子状态之间的转换,采用层次化状态机后只需要一个全局变量和三个仅在各个层次内使用的全局变量,当系统的状态越多,层次划分得越细时,层次化状态机所起的作用会越加明显。综上,层次化状态机就是在系统软件设计中把面向控制和面向数据的程序加以区分,状态机主要用于捕获程序的控制流,层次化的状态机有助于程序的控制流更加清晰易于控制,而算法和重要的数据结构等数据运算,则被另外单独处理。
3 系统设计与层次化状态划分
3.1 程序任务及状态划分
对于各个状态的结合要灵活多变,做到中断可以随时响应。对于不同的错误,系统要做出相应的反应,进行实时报错,以便于软件的维护。分析整机系统可以将手操器的软件任务划分为4大类:①按键识别、响应程序;②USB通信程序;③界面显示;④电源监控程序。系统主要是在按键识别、USB通信、液晶显示这三大状态之间切换,图4说明了层次化状态机的划分方式。
图4 系统层次化状态划分
具体可细分为:
① 按键识别。最底层的按键状态识别的转换,按键检测(等待状态)、键值确认(消抖状态)、按键释放(等待释放状态)三种状态,其状态转移图如图2所示;根据键值和当前状态解码成对应的功能。全键盘设计包括了18个按键,按键响应程序根据按键的不同功能分为7种不同的状态,主要针对液晶显示中的菜单切换、数字显示以及USB通信的确认等。
图5 菜单抽象成的多叉树结构
② 界面显示。根据按键不同的界面显示和执行的功能也不同。根据按键命令做相应的上、下、左、右翻页和数据显示,由于是点阵液晶菜单显示,还会划分许多状态,这是下一层次的状态转换。
对于USB通信任务,由于该任务无法再细分,任务运行时独占整个控制权,即在进行USB通信的时候,系统不做按键检测和按键响应。
3.2 软件可靠性分析
软件设计中使用有限状态机的思想,并采用基于头文件接口的模块化程序设计,模块与模块之间是独立的,模块与模块之间的通信连接通过各个模块的头文件进行。层次化状态机的引入和模块化编程的使用使得程序中全局变量的应用减少,降低了因全局变量过多造成程序运行错误的可能性,增加了软件的可靠性。
其次,层次化状态机思想是在系统任务调度上加快系统的反应,增加系统的实时处理能力,在宏观上增加任务执行的并行性。层次化状态机的使用使软件设计中很容易并且及时地进行任务切换与调用,使实时性要求高的任务及时响应。对比于按顺序结构的软件架构实时处理能力更强。按键响应和USB通信能及时响应。
最后,当运行USB通信任务,为确保数据通信成功,本次任务运行时独占整个控制权,即在进行USB通信的时候,系统屏蔽按键检测和按键响应等其他有可能干扰通信的任务。
4 系统菜单设计
4.1 液晶显示总体方案设计
本设计最直观的部分就是点阵液晶菜单显示。根据涡街流量计所需要的参数,结合设计中所使用的160×160点阵式液晶,界面设计采用多级菜单的形式。菜单设计内容选项子级菜单层数较多。首屏包括有仪表参数设置、仪表参数下载、4~20 mA上下限调整和电池电量查询,每一项都有后续分支,在各个分支中需要设置数据或者有数据显示的各项,在各项名称后用冒号加以区别。
4.2 基于二叉树链表菜单显示设计的改进
有限状态机在图形界面的菜单显示中也发挥重要作用,可以把每级菜单界面看成同一层次的状态集合,同层次的项目为本层子状态,同一屏菜单的同级翻动为同层状态的互相转换,上下级菜单显示是不同层状态的转换。
菜单设计中经常采用树形拓扑结构法。这种树形拓扑结构是多叉树,如图5所示。由于每个菜单会有不同个数的子级菜单,所以采用统一的数据结构来描述多叉树的这种相互关系比较困难,其中一种较好的方法是把多叉树变为二叉树结构。
链表法优先选用在二叉树结构的程序上。此时每个节点中,除了有用的信息外,还要存有至少三个指针,分别指向上级菜单、本级菜单、下级菜单,当显示某以中间级菜单时很容易从指针链表中查找到其上下级菜单,进而切换。因此本设计中菜单有65个选项,这意味着那些只是为了维持树形结构而存在的指针就有195个,这种方法对于单片机的资源要求较为苛刻,占用较多单片机资源,使其他任务的执行受限,而且采用链表法表示二叉树在本课题中需要用到结构体变量的常量数组,这种数据结构在所用编译器中不支持。
基于单片机的有限资源和菜单设计的特点,在进行菜单设计时,为菜单中每一个选项设定唯一编号,称为菜单选择值。并将其抽象成图6所示的二叉树结构,由数字相对应。容易看出图6中每行相连的几个编号既是同一界面总的不同菜单选项,例如,编号4与6相连,则对应包含流量监测、仪表参数读取及设置这一界面。从图6中很容易看出本级菜单和上下级菜单的联系,因此用一维数组即可来实现菜单的树形结构,也就是利用数组自身下标编号和数组值之间的逻辑关系来代替维持树形结构所需要的链表指针,在菜单数组中只存下级菜单值[9]。
图6 改进后的二叉树关系图
用一维数组表示二叉树关系,表略——编者注。可以用数组单元的下标号作为本级的菜单值,该级的下级菜单值可以存在相应数组单元中,因此不再需要指针来确定一组上下级菜单关系,至于本级和上级菜单的关系,可以反推演得知,即查找数组值等于本菜单编号的数组单元对应的下标号。每当要选择包含有下一级菜单的选项时,只需要把它的下一级完整显示出来,然后再上下移动光标,就可以找到所有下级节点对应的选项。
用一维数组表示二叉树结构比用链表更加节省空间,就65级菜单来说,至少节省130字节的空间。在执行速度上,当查找当前菜单的下级菜单时两者相当,查找当前菜单的上级菜单时一维数组表示方法需要从开始查找数组,此种情况总体来说时间略长,最少查找1次,最多要查找30次。但对实时显示没有多大影响,还能节省较多空间,因此一维数组表示链表的菜单设计方法是有效的。
结语
程序设计工作中,主要从三个角度进行设计:一是系统任务调度方面,为了加快按键响应速度,提高系统实时性能,同时不影响USB通信和其他模块的运行,采用层次化状态机思想,根据执行任务的状态进行划分并将联系紧密的状态划分在同一层次内。系统定时作为查询周期,在系统时钟节拍的驱动下,系统在状态(任务)之间有效的转移。二是在程序结构方面,采用头文件接口的模块化程序设计,减少了程序中全局变量的使用,提高了模块的内聚性。三是采用改进型二叉树链表结构进行菜单设计,使界面显示和切换更加条理和高效。通过层次化状态机使用,提高了软件的实时性、可修改性,最重要的是提高了程序的可靠性和可维护性。