1导言
大多数嵌入式体系,仅供给几个按键和像素点较少的LCD,一起处理器运算才能有限(如8/16位单片机),不宜运转商用的GUI图形库(如uC/GUI、miniGUI、QT等),但仍然得为用户供给GUI功用。一个具有代表的硬件渠道如下,供给6个输入按键:上移、下移、左移、右移、确认和撤销;有一LCD,不约束物理尺度与像素点数。本文描绘一种依据上述硬件渠道的完结简略的GUI规划原理,它供给窗口体系因而具有较好地显现作用。
2硬件规划
一般LCD显现模块包括三部分:操控器、驱动器和液晶显现屏,一起供给外部引脚供嵌入式处理器衔接。以TRULY公司LCD显现模块MST-G320240DBSW-75W-E为例,它的操控器为RA8835,模块的引脚界说如下表1。[1]
表1 LCD引脚示例
硬件规划需求将LCD模块引脚正确衔接到处理器操控引脚上。关于大部分单片机来说,将LCD模块引脚衔接到一般I/O口是比较好的挑选,如图1显现了AT89S52微处理器衔接20引脚的LCD模块的原理图。
图1 MCU的I/O衔接LCD模块
另一种高档接线办法是将它衔接到Asynchronous Memory接口(假如处理器具有),这样一来操作LCD就像拜访一般的存储器(如FLASH)相同,极大供给便利性,如图2所示。
图2 ASYNC MEMORY衔接LCD模块
3 LCD驱动
LCD操控器是LCD模块的中心,驱动一个LCD模块实质便是对LCD操控器写一系列指令的进程。[2]
图3总线时序
图3是LCD操控器RA8835的总线时序。关于一般I/O口衔接LCD的办法,驱动程序需求对相应引脚按次序发生凹凸电平,如下代码所示:(省掉对引脚宏界说的句子)
void lcd_cmdwrite(unsigned char cmd)
{
LCD_CS = 0; /* Enable access LCD */
LCD_CD = 1; /* 0=Data; 1=Command */
LCD_WR = 0; /* Enable write */
LCD_RD = 1; /* Insure read signal is invalid */
LCM_DATA = cmd; /* Put command value into port */
LCD_WR = 1; /* Disable Write */
LCD_CS = 1; /* Disable access LCD */
}
假如嵌入式处理器的Asynchronous Memory接口衔接到LCD总线,需求设置该接口的延时时刻,以便于契合图3中LCD的总线时序,然后驱动将会简化成写外设内存。针对图2中接线,写LCD指令寄存器的驱动代码如下:
#define LCD_START_ADDR 0x20100000 /* BANK1 */
#define LCD_DATA_ADDR (LCD_START_ADDR) /* Data */
#define LCD_REG_ADDR (LCD_START_ADDR+2) /* CMD */
#define p_wLcdDataAddr ((REG16*)LCD_DATA_ADDR)
#define p_wLcdRegAddr ((REG16*)LCD_REG_ADDR)
#define WR_LCD_REG(wRegVal) *p_wLcdRegAddr = wRegVal;
LCD操控器指令一般安排成寄存器格局:寄存器名+数值。仍以上例为参阅,操控器RA8835设置光标地址的指令为:寄存器名(CSRW)0x46,数值为2个字节(光标方位)。其间寄存器名写入指令输入缓冲器内(即A0=1),数值写入数据输入缓冲器内(即A0=0)。
在一个LCD上制作任何图形或文件的根底是制作像素点,因而首要需求完结的功用是操作像素点。操作一个像素点的接口是:X坐标、Y坐标和动作(点亮或擦除),算法如下:
1. 依据X坐标和Y坐标组合成LCD光标值并写入LCD操控器;
2. 从LCD操控器中读取当时光标下RAM数值;
3. 依据动作(点亮或擦除)修正RAM数值对应像素BIT值;
4. 再次将光标值写入LCD操控器(读RAM导致该光标已移动);
5. 将修正后数值写入LCD操控器的RAM区。
一旦完结像素操作就能够发挥一些高档制作动作:文字、图片、几何图形等。
4 GUI软件结构
图4显现了本GUI规划的软件层次,引进分层会带来许多优点:[3]
下降复杂度每一层只专心自己需求完结的功用,完结高内聚;
进步可移植性不论替换处理器仍是LCD只需求修正底层部分;
改进功用运用高效算法来优化功用只需求修正一处。
图4 GUI软件层次
关于轻量级嵌入式GUI来说,窗口是十分重要的图形载体,嵌入式GUI一般一个屏幕仅包容一个窗口,当时正在显现的窗口即为活泼窗口,其它均为睡觉窗口。因而窗口有2种状况:
活泼期:处理音讯,呼应动作,如获取实时数据并改写屏幕等;
睡觉期:不呼应外部音讯,开释资源,如硬件和软件实体等;
从逻辑上把窗口体系分红2层:窗口服务器和客户端,如图5所示。外部音讯(用户按键、数据更新等)首要传递给窗口服务器,然后服务器把音讯传发给当时活泼窗口,活泼窗口依据音讯类别进行相应处理;别的,活泼窗口也能够向服务器宣布恳求,如切换窗口等。
图5窗口服务器与客户端
在GUI规划中音讯是各种目标通讯的重要机制,窗口之间通讯的品种繁复,假如对音讯进行编码呢?图6显现了一种参阅办法。音讯实质上便是一个32位整数,其实许多RTOS音讯传递也是这个类型。取低8位为事情编码,高24位为类型编码。[4]
任一类型最大支撑256个事情,类型编码仅能一位为1,否则将引起事情判别过错。当编码正确时,类型一定是2的整幂次,因而能够运用查看整幂次方的算法来检测音讯正确性。
设uMsg是音讯数值,则有:
uTemp = uMsg & 0xFFFFFF00UL; /*取类型编码值*/
if (0 == (uTemp & (uTemp – 1)))编码正确
else 编码过错
图6音讯编码
5窗口体系与交互
用面向目标的办法来规划窗口如图7所示,每个窗口都有自己的ID,一起有其周围街坊窗口的ID值用于窗口切换;私有数据空间用于窗口的个性化定值。窗口目标包括3个办法:Init()用于制作窗口和初始化窗口资源;ProcMsg()处理一切传递到本窗口的音讯;Close()封闭窗口一起开释资源。
图7窗口目标规划
把多个窗口的指针安排成数组就形成了图8所示的窗口目标群,这样一来便利窗口的寻址。
图8窗口目标群
图9显现了窗口与街坊窗口的联系,假如当时活泼窗口为11,呼应用户按键上/下/左/右来切换窗口时,能够直接取对应街坊窗口的ID,这样操作带来极大的快捷性。
图9窗口与街坊窗口寻址
6 状况栏完结
状况栏一般坐落窗口的最底部,它的典型结构如图10所示。它一般供给如下办法:
Init():初始化状况栏目标;
Visible():显现状况栏目标,实时呼应外部音讯;
Invisible():不再显现状况栏目标,疏忽外部音讯;
ChangeLinkStat():更新联机/脱机状况;
UpdateDate():更新当时日期
UpdateTIme():更新当时时刻
私有显现空间是供给给窗口进行个性化定制,它的原则是:不管哪个窗口运用,都是“谁分配,谁收回”,即当该窗口封闭时需求铲除它在私有显现空间的一切显现内容。
图10 状况栏
7 结束语
本文规划的轻量级嵌入式GUI已经在某工业操控产品中安稳运用多年,该产品选用TRULY公司320×240像素的LCD。选用分层与面向目标的规划,使软件体系简单移植和开发;简略化的规划使体系反常安稳;别的占用资源很少,这是商业GUI无法比拟的。在此根底上还能扩展更高档的图形控件功用,能够拜见姊妹篇《轻量级嵌入式GUI高档功用完结》。