随着嵌入式系统中硬件集成度的不断提高,嵌入式软件在嵌入式系统开发与设计中的地位越来越重要,然而目前在嵌入式软件开发中流行的面向过程的程序设计方法已难以满足某些复杂应用的要求。由于嵌入式软件有着高互动性和严格实时性等特点,利用事件驱动的反应式系统和层次式状态机对其进行建模和描述是非常合适的,所以有一种轻量级、可配置、紧凑的建模工具是十分必要的。Miro Samek等人提出的量子平台(Quantum Platform, QP)[12]恰好能够满足以上所有的特性。
本文探讨了量子平台的体系结构和编程思想;以相量测量装置(Phasor Measurement Unit,PMU)的软件系统为应用对象,具体介绍了基于量子平台的软件设计及编程实现;并对全文作了总结。
1量子平台简介

图1量子平台结构
量子平台是一种事件驱动的轻量级软件架构。如图1所示,QP由以下各部分组成[1]:
① 量子事件处理器(Quantum Event Processor,QEP)[1]。QEP是用编程语言描述的UML状态机。它完全支持层次式状态嵌套,支持带有任意参数的事件,专门针对静止状态转移进行了优化,可以容易地整合任意的事件队列和分发机制。其良好的代码设计使得状态机实例在RAM中仅需一个函数指针和一个状态标志字节。另外,各种状态和转移形式均被限制在编码空间(ROM)中,无需占据RAM中的空间。
② 量子框架(Quantum Framework, QF)[2]。QF是公用的事件驱动应用框架。QF将事件驱动系统划分为可由QF管理的活动对象。活动对象被任务所封装,各活动对象之间通过异步事件交换来通信。这些事件均以量子节拍被有序响应,事件交换和排队的细节由QF所封装。QF在事件交付时遵循出版订阅模型,并根据需要对事件队列进行先进先出式(FIFO)和后进先出式(LIFO)排队;QF还实现了事件交付时的零拷贝和自动事件回收,并支持任意数量的周期/非周期事件定时器以及确定长度的事件队列和事件池。
③ 量子内核(Quantum Kernel, QK)[3]。QK是一种基于抢占式优先级的实时微内核,可为QF提供多线程服务。相对于传统的抢占式优先级实时内核,QK更为简洁和高效。QK最多支持64个任务同时执行,支持量子节拍无阻塞机制和天花板优先级互斥信号灯机制。所有基于QF的任务和中断共同使用一个栈。
④ 量子内窥器(Quantum Spy, QS)[4]。QS是一种与QEP、QF和QK等组件集成的实时运行跟踪工具。QS通过日志记录的方式,获得所开发的程序内部状态机、框架、内核和应用代码的运行情况,并提供精确时钟标签,复杂的事件运行过滤器以及日志数据的高压缩。
由此可见,量子平台有着许多优秀的特性[5](如简洁、实用、易配置、良好的可观测性、可控制性和可测试性等)。
2基于量子平台的PMU软件设计
PMU是一种新兴的电力数据智能实时采集装置[3]。典型PMU抽象模块图如图2所示。PMU利用由高精度时钟源同步产生的全系统同步时钟对电力系统测量点状态量进行采样。模拟信号由电压和电流互感器的副边得到,并经过抗混叠滤波及浪涌滤波后,由A/D转换器转换为数字信号交给CPU处理。CPU采用一定的信号处理算法,得到量测点的状态值,并依照一定的格式将测量信息及相应的时间标签打包,通过通信端口输出。

图2典型PMU抽象模块图
分析图2可知,在硬件平台搭建好的基础上,PMU软件需要具备以下功能:
◇ 原始数据的采集和缓存;
◇ 对原始数据进行一定的加工;
◇ 目标信息的缓存和输出(远程输出、本地显示、本地存储);
◇ 本地控制和远程控制。
通过分析可以确定,系统需要采样活动对象类(Sampling)实现对原始数据的采集;需要算法活动对象类(Algorithm)对原始数据进行处理;需要输出活动对象类(Output)按要求输出数据。另外,系统还需要专门的活动对象实现对共享资源的控制。这里用原始数据缓存活动对象(RawDataCache)封装原始数据,并控制Sampling和Algorithm对原始数据的访问;用同步相量信息缓存活动对象(SPFCache)封装目标信息数据,并控制Algorithm和Output对目标信息的访问。本地和远程的输入控制均通过中断服务程序实现。
PMU中的时钟同步模块将交由QF处理。可以专门为时钟同步设一个定时器,当秒脉冲信号到来时,触发秒脉冲超时事件;QF将这个事件插入到接收者的事件队列中,以便进行与秒脉冲超时有关的处理。
下面以处于实时运行状态的PMU为例,用基于QP的设计方法建模并分析。
各活动对象运行时的顺序如图3所示。各活动对象在周期时间信号的驱动下进行相应的动作。由图3可以很容易地得到各活动对象的状态及其之间的事件交互。

图3PMU软件运行顺序图
图4为PMU活动对象类继承关系图,图5为各活动对象类图。所有的活动对象均由QActive类继承而来。QActive不仅继承了量子层次状态机(QHSM)的所有性质,还内嵌了量子事件队列(QEQueue)和线程实例。各活动对象可根据系统需求定义自身的属性及状态转移方法。

图4PMU活动对象类继承关系图

图5各活动对象类图
各活动对象的状态转移图如图6~图10所示。由于各活动对象的进入和退出均为缺省动作,故图中未注明。下面对这5类活动对象进行分析。

图6Sampling状态转移图图7RawDataCache状态转移图

图8Algorithm状态转移图图9SPFCache状态转移图

图10Output状态转移图
(1) Sampling
Sampling初始化后处于work状态。在PeriodTimeout驱动下,Sampling向下一个原始数据缓冲池中写数据; SwitchAct是采样开关动作信号,在SwitchAct驱动下,Sampling开始对新的采样点进行采样。
(2) RawDataCache
RawDataCache正常运行时处于serving状态。在PeriodTimeout驱动下,RawDataCache需要向原始数据缓冲池中写入本次采样时间值。当多个Algorithm发送hungry请求信号时,RawDataCache调用QP内核进行资源分配决策。
(3) Algorithm
Algorithm初始化后进入sleep状态。当PeriodTimeout信号到来时,Algorithm转入ready状态并向RawDataCache和SPFCache发送Hungry信号请求并等待资源分配;当RawDataCache和SPFCache发送的Work信号都到来后,Algorithm转入work状态,随后开始执行相应的动作。算法动作执行完毕,Algorithm向RawDataCache和SPFCache发送Done事件;当接收到RawDataCache和SPFCache发送的ACK信号后,转入sleep状态。
(4) SPFCache
SPFCache处于serving状态,但是由于SPFCache要同时与各种Algorithm和Output进行交互,因此所响应的事件和执行的动作最多。在一个或多个Hungry信号的驱动下,SPFCache调用系统调度内核为Algorithm进行资源分配决策。当接收来自Algorithm的Done信号后,SPFCache根据各个Output实例的优先级来决定系统资源分配。当远程输出因各种原因传输失败后,远程控制端会向本地PMU发送NACK命令,这个输入中断会向SPFCache发送NACK事件;SPFCache接收到NACK事件后,将当前相量信息缓冲池指针指向对应的缓冲池地址,然后向Remoteout发送Work事件以重新启动远程传输线程。
(5) Remoteout、Storage和Display
这3个活动对象实例均由Output类产生。根据PMU输出实时性的要求,Remoteout、Storage和Display的优先级依次降低。Remoteout和Storage均有实时性要求,而Display没有实时性要求。当3个活动对象竞争资源时,SPFCache根据其优先级大小发送相应的Work信号。
3总结与比较分析
下面总结一下基于QP的嵌入式软件设计的主要实施步骤。
① 软件系统结构量子化: 明确划分活动对象。
② 软件运行状态量子化: 制定活动对象运行顺序图。
③ 实体静态结构量子化: 制定各活动对象的类图、各个类资源间的相互关系及用于交互的各种信号和事件。
④ 活动对象动态行为量子化: 建立各活动对象的层次式状态机模型,同时得到其状态转移图。
⑤ 实体配置量子化: 明确各活动对象优先级,确定各种内存缓冲(如事件队列、事件池和堆栈)的大小。
⑥ 编码,调试与修改。
由上可知,量子平台在建模和实现步骤上与传统面向过程的方法有很大差别。其本质基于层次式状态机,是对面向对象设计方法的改进。
将基于QP的软件开发与传统的多线程开发相比较,可以发现:
① 传统的多线程软件利用某些方法来保护共享标志,使得对这些标志的访问是互斥的[45]。这种共享及同步机制的设计方法,要求深刻理解时间域,以及支持线程间同步和通信的操作系统机制。一旦引入微妙的、难以再现、隔离和修正的错误,后果是非常严重的。
② 基于QP的软件采用了量子节拍机制和异步事件交换机制,巧妙地避免了上述问题[6]。活动对象使用量子节拍,每次处理一个完整的事件。这种机制固有地排除了内部的并发问题,所以在实现一个活动对象的内部结构时,不必关心多线程资源共享及同步的问题。而且特定的活动对象与其对等实体的事件交换是异步的。当某个活动对象正在运行时,任何与资源调度有关的事件都将自动排队。只有当前的量子节拍执行完毕后,系统才能执行接下来的调度。这种机制的运用避免了死锁。从系统全局运行效率来看,基于QP的软件比传统的多线程软件好得多。
当然,基于QP的设计方案其编码及执行空间可能比传统的方案要大一些。但是,基于QP的代码结构是简单的,因而避免了所有的并发危险,而且在最大程度上保证了资源分配的公平性,同时又具有很好的灵活性和可伸缩性。相比较而言,基于QP的多线程设计更具有优势。
结语
作为一种事件驱动的软件架构,QP显得十分紧凑和简洁。基于QP的嵌入式软件开发以层次式状态机为模型,利用UML中的顺序图、类图以及状态图实现模型的建立与描述。由于采用了RTC机制和事件异步交换机制,因此较传统的多线程而言,基于活动对象的多线程软件有效地避免了死锁,大大提高了软件的运行效率,并使得PMU软件系统具有良好的开放性、可观测性、可控制性以及可调试性,能够更容易地实现分布式系统。因此,QP非常适合实时性、可靠性和稳定性要求较高的嵌入式应用领域。