1 引 言
在工业控制领域里,各种仪器仪表、智能工控设备也广泛采用了嵌入式技术,但由于资源有限, 这些系统一般不希望建立在庞大累赘的、非常消耗系统资源的操作系统和GUI之上,比如Windows或X Window。这些系统对轻型GUI的需求更加突出。因此,在工业控制系统中实现一个简洁、快速、方便的嵌入式GUI系统具有广阔的市场应用前景。
嵌入式系统往往是一种定制设备,它们对GUI的需求也各不相同。有些系统只要求一些图形功能,而有些系统要求完备的GUI支持,所以嵌入式GUI必须呈模块结构,便于配置和定制。本文根据嵌入式系统的特点提出一种嵌入式GUI的实现方案,通过本方案设计实现满足工控要求的嵌入式GUI系统不仅具有很好的通用性,还具有轻型、占用资源少,高性能,高可靠性,可配置等特点,可以方便地移植到各种工控嵌入式系统中。
2 嵌入式GUI系统的关键技术
2.1 消息驱动机制
所谓的“消息驱动”或 “事件驱动”,就是用户可以用鼠标点击任意的窗口和控件,也可以用键盘在当前输入焦点输入内容;由用户主导程序下一步如何操作,而不是像字符时代那样由程序来主导用户。嵌入式GUI采用了这一思想,以消息驱动机制为核心,把GUI系统的各个组成部分有机地结合起来。
2.2 窗口管理技术
为了实现对多窗口的支持,即允许用户把内容显示在不同的、而且可以重叠的窗口区域内,这必然涉及到各个窗口在屏幕上的层叠顺序,需要GUI系统提供一种有效的窗口管理机制,我们采用一种称为窗口Z序的机制来进行管理。
2.3 实现平台无关性
嵌入式系统应用的领域不同,要求的GUI底层设备也不同,为了便于GUI移植到不同硬件平台,应设计隔离硬件设备的硬件抽象层。它定义了一组不依赖于任何特殊硬件的抽象接口,所有顶层的图形操作和输入处理都建立在抽象接口之上。它位于硬件设备和软件之间,实现对显示输出设备(如LCD显示器)、用户输入设备(键盘、触摸屏)的控制,向GUI上层软件提供统一的编程接口。我们封装了硬件抽象接口的实现函数,移植到不同的硬件,只需考虑修改直接和硬件打交道的几个函数即可,移植者无需关心硬件抽象接口的实现。通过这个设备硬件抽象层隔离具体的物理实现,以实现GUI硬件无关性。
3 嵌入式GUI的体系结构
根据上面的分析,嵌入式GUI系统采取分层设计的结构,其分层结构图如图1所示。
从图中可以看出,最底层GAL和IAL是与底层输入输出设备接口,便于GUI挂接不同的输入输出设备,实现GUI系统良好的可移植性和通用性。中间的核心层CORE包含了嵌入式GUI全部功能的算法。上层是API层,提供操作各种GUI对象(如窗口、菜单等)的应用编程接口函数。
4 嵌入式GUI核心层的总体设计
GUI核心层主要由三个子系统组成,分别是服务管理子系统、事件管理子系统、窗口管理子系统,各子系统相对独立又彼此联系。图2为GUI系统核心层的实现框架图。
4.1服务管理子系统
4.1.1 图形设备接口
图形设备接口(GDI)是建立在图形输出抽象层上的一个独立的绘图应用接口,它将图形输出抽象层提供的接口功能进一步封装和扩充,向更高层的应用程序接口提供使用更为简便,功能更为完善的绘图功能。GDI提供的图形服务包括:基本绘图原语、文本和字体支持、图像格式支持、其他高级图形功能。
4.1.2 内存堆管理
内存堆管理是为了避免在系统运行过程中动态分配和释放内存时引起存储碎片。
4.1.3 定时器管理
系统的时间管理需采用定时器管理来实现。当用户需要定时的处理某项操作将会使用该模块,在系统中也有使用,如编辑框控件中光标的闪烁等。
4.2 事件管理子系统
事件管理子系统主要以消息驱动机制为核心,负责定义、分发、处理所有的GUI事件。事件管理子系统支持GUI对象间通信和GUI系统与GUI外部系统间通信。
4.3 窗口管理子系统
窗口管理子系统负责创建、删除、管理各种窗口,实现各种预定义窗口(控件)逻辑,进行裁剪以保证多窗口的正确显示,以及各种窗口逻辑事件的产生和处理。
4.3.1 屏幕和窗口管理
窗口是GUI的基础,一切的GUI操作都是在窗口的基础上完成的。在用户主任务中,我们首先建立一个基准窗体,覆盖整个LCD显示屏幕,此窗口可称为桌面,然后在其上建立其他任务窗口以及子窗口。窗口管理支持多线程,以方便进行窗口的移动、大小改变、隐藏恢复、焦点切换等,并最终维护由于多窗口操作引起的Z序变化。窗口管理主要负责窗口的绘制、窗口的重画及消息处理。
4.3.2 基本控件
控件可以理解为主窗口中的子窗口。一般地,GUI系统都会预先定义一些控件类,当利用某个控件类创建控件之后,所有属于这个控件类的控件均会具有相同的行为和外观。利用这些技术,可以确保一致的人机操作界面;而对程序员来讲,可以像搭积木一样地组建图形用户界面。本模块提供了常用的预定义控件类,包括按钮、单选框、复选框、静态框等。
5 嵌入式GUI系统核心层的具体设计与实现
5.1 窗口剪切算法的设计
GUI采用窗口剪切算法来支持多窗口风格。窗口剪切算法以矩形为基本单位来表示剪切域,算法以设备上下文中全局剪切域、局部剪切域和有效剪切域等属性,根据一定的工作机制来限定图形输出区域,任何超过该设备上下文输出区域的部分均被裁剪。底层图形引擎在进行输出时,根据当前输出的剪切域进行输出的剪切操作,从而保证了窗口间重叠也不会混乱。
GUI系统一般利用Z序来管理窗口之间的互相剪切关系,根据窗口在Z序中所处的位置计算每个窗口的剪切域。我们可以将某个窗口全局剪切域归纳为原有剪切域中排除某个矩形而生成的:窗口的全局剪切域初始化为窗口矩形;当窗口之上有其他窗口覆盖时,则该窗口的全局剪切域为排除新窗口矩形之后的剪切域;沿Z序迭代第2步,直到最顶层窗口。
显然,在剪切域非常复杂,或者窗口非常多时,需要大量的矩形来表示每个窗口的全局剪切域,为支持运行时大量的剪切运算,剪切域的实现采用动态内存分配。
而在C程序中,如果频繁使用malloc和free申请和释放每个剪切矩形,将带来许多问题。第一,malloc和free是非常耗时的操作:第二,频繁的malloc和free将导致C程序堆的碎片化,从而可能导致将来的内存分配失败。为了避免频繁使用malloc和free,在初始化时,建立了一个私有的堆,自行管理剪切域数据块的申请和释放。我们可以直接从这个堆中分配剪切矩形,而不需要从进程的全局堆中分配剪切矩形。这个私有堆实际是由一些空闲待用的剪切矩形组成的。每次分配时返回该链表的头节点,而在释放时放进该链表的尾节点。如果该链表为空,则利用malloc从进程的全局堆中分配剪切矩形。
与排除矩形相反的操作是包含某个矩形到剪切域中。这个操作用于隐藏或者销毁某个窗口时。当一个窗口被隐藏或销毁时,该窗口之下的所有窗口将受到影响,此时,要将被隐藏或销毁窗口的矩形包含到这些受影响窗口的全局剪切域中。可设置一个函数专用于该类操作。为确保剪切域中矩形互不相交,该函数首先计算与每个剪切矩形的相交矩形,然后将自己添加到该剪切域中。
5.2 消息驱动机制的设计与实现
5.2.1 消息队列及消息循环的设计
GUI系统的每个输入设备随时可能产生输入事件,同时系统内部也可能发生各种事件, GUI系统的输入层接收到这些事件后就合成各种不同的消息,然后向上传递。对于操作系统来说只能顺序地向应用程序传送消息,因此,若同时出现多个事件,必须有一个机制来管理这些同时产生的事件。在GUI系统中这种机制就称为消息队列,按照事件的时序把它们的消息送入队列,窗口系统再依次向应用程序发送。消息队列的数据结构为一个全局的循环队列,同时定义一组基于该循环队列的操作:初始化消息队列、清空消息队列、压入消息队列和弹出消息队列等等。在实际设计消息队列时要考虑消息的传递方式、优先级和特殊消息的处理等问题。
GUI系统采用消息驱动的框架结构;应用程序建立一个循环,GUI不断轮询消息队列,把获得的消息根据消息路由算法进行分发和投递,送达目的对象,由目的对象提供消息处理。处理结束后,重新进入消息循环,直至退出消息出现,消息循环的流程如图3所示。
如果消息队列为空,GUI将优先等待外部事件的发生,然后把等待到的事件(外部输入事件或超时事件)封装为消息压入消息队列。窗口在创建时一定要提供一个消息处理函数,用户在该函数中对每一个关心的消息作出判断和处理。
5.2.2 消息路由算法
GUI的消息路由基本主线(自顶向下):桌面-->某个主窗口-->某个控件。系统消息路由算法包括键盘路由算法和鼠标路由算法。
6 用户应用程序举例
图4给出的是一个典型的嵌入式GUI方案设计的流程图。假设这个系统有n个页面,每个页面有若干GUI元件。当有消息或事件时,系统进行消息处理,如需转换界面进入下一界面,系统则进行窗口之间的切换,包括窗口的关闭、剪切、删除、隐藏等动作。
7 结束语
本文详细介绍一种为工业控制嵌入式系统应用而开发的的轻量级、功能丰富、易定制、易移植的图形人机界面开发包,与同类产品相比具有代码量小、执行效率高的特点。用C语言编写的GUI程序可以方便地移植到各种工业控制嵌入式系统中,使用简单、通用性好,能满足一些较复杂界面显示的需要,其已运行于基于ARM微处理器的嵌入式硬件平台之上,已经在工控嵌入式系统中得到应用。实用表明,我们设计的GUI系统运行良好,很好地满足了人机交互界面的要求。
原文地址:http://www.hqew.com/tech/fangan/1547607.html