摘要 MiniGUI是一种轻量级的针对嵌入式操作平台的图形用户界面支持系统,广泛应用于基于ARM、MIPS等主流嵌入式开发平台的项目及产品中。本文详细介绍嵌入式系统中人机交互常用输入设备(4×4数字小键盘)在MiniGUI中的实现方法,包括相关的底层按键扫描驱动程序,键盘输入引擎的编写,以及如何在MiniGUI中添加新输入引擎的方法等;最后针对调试过程中的典型问题提出一些调试建议。
关键词 MiniGUI输入抽象层 输入引擎数字键盘
嵌入式系统通常拥有特定的输入设备。输入设备用于实现数据输入和人机交互,其种类繁多,并且不同的设备依赖不同的硬件实现。为了减弱系统的硬件相关性和提高可移植性,MiniGUI提供了统一的输入抽象层IAL(Input Abstract Layer)接口来支持不同的输入设备,减小了开发输入设备的难度。下面以开发4×4小键盘输入为例,介绍在MiniGUI中开发和实现特定键盘输入设备输入的方法。
1 MiniGUI对键盘输入的处理方式
MiniGUI对键盘输入的处理方式如图1所示。键盘设备驱动程序从键盘接收原始的输入事件和数据,并把它转换为MiniGUI抽象的键盘事件和数据。相关的底层事件处理例程把这些键盘事件转换为上层的击键消息,放到相应的消息队列中。应用程序通过消息循环获取这些消息,交由窗口过程处理。
开发特定的键盘输入,主要完成底层的两部分工作:键盘驱动程序设计和键盘输入引擎开发。前者负责从键盘接收原始输入事件和数据,后者负责把原始的输入事件和数据转抉成MiniGUI抽象的键盘事件和数据。至于抽象键盘事件和数据转换成上层的击键消息等工作,则是由MiniGUI提供的底层事件处理例程自己完成,无需用户设计,这正是MiniGUI提供输入抽象层接口(IAL)所带来的好处。下面具体介绍小键盘输入的开发过程与实现方法,主要介绍重要接口函数的实现。
2 键盘驱动程序设计
该设备驱动要实现的主要功能是进行小键盘行列扫描,接收原始键盘输入事件和数据,如有无键按下、按下某键或释放某键。返回的字符型按键信息(小键盘扫描码)由两部分组成:“高位”代表键盘输入事件,即按下(高位为O)或释放(高位为1);“低7位”代表键盘输入数据,即按下或释放的按键值。
2.1 键盘按键值的获取
当按下某个键时,和该键所在行列相连的两路通用外设I/O引脚就会导通,其电平就会相同,因此驱动中只需要轮询各路I/O引脚就可以知道按键值。比如,使各行线输入低电平,各列线都通过上拉电阻接高电平,此时检测各列,如果某一列电平为低,则说明该列所在的键盘已经按下,使该列与行导通变为低电平,这样就可以确定按键所在列号(j);同理,将各列置低电平,再依次查询各行,就可以确定按键的行号(i)。若定义一个键值映射数组key_arrow[5][5]表示所有键盘按键值:Key_arrow[5][5]={{0,O,O,O,0,0},{0,‘7’,‘8’,‘9’,‘A’},{0,‘4’,‘5’,‘6’,‘B’},{0,‘1’,‘2’,‘3’,‘C’},{0,‘D’,‘O’,‘.’,‘E’}},则按键值就为key_arrow[i][j]。初始化时行列号均为0,因此当小键盘无键按下时,返回按键值为0(即字符NULL)。
需要注意的是,要保证驱动正常工作,设置好行列线的输入输出模式后,需要一定时间延时以后才能开始进行行(列)查询。这是因为行列线进行输入输出模式切换时存在硬件延迟。
2.2 键盘扫描码的获取
为了判断键盘事件是按下还是释放,定义两个无符号型字符变量last和key。前者是静态变量,存放等待释放的键的按键值,即前一次扫描读到的按键值;后者存放当前键盘扫描码。当键盘事件为按下时,它的值和键盘按键值相同;当键盘事件为释放时,它的值等于last高位置l后的值。
2.3 功能实现流程
我们用驱动程序read接口函数实现这些功能。当应用程序凋用read函数后,该函数先进行行列扫描,得到键盘按键值key_arrow[i][j]后进行判断。著其非零,即有键按下,则直接将此按键值作为键盘的扫描码(key=key_arrow[i][j]),并将其赋给字符变量last,表示该键等待释放。如果key_arrow[i][j]为零,即无键按下,则判断是否有需要释放的键:若没有(即last为O),就直接将按键值(key=0)作为键盘扫描码;若有键需要释放(1ast非零),就把1ast高位置1作为键盘扫描码(key=last 10x80),表示释放刚按下的键,然后last清零,表示已没有按键等待释放。read函数最后发送键盘扫描码(key)到用户缓冲区后返回。
3 键盘输入引擎的设计
第2部分要开发的是小键盘输入引擎。它负责把键盘驱动提供的原始键盘输入事件和数据(即小键盘扫描码)转换为MiniGUI抽象的键盘事件和数据(由系统扫描码索引的键盘数组)。
3.1 MiniGUI的IAL接口
前面已提到,IAL定义了一组不依赖于任何特殊硬件的抽象接口,而用于实现这一抽象接口的底层代码就称为输入引擎。在代码实现上,MiniGUI通过INPUT结构来表示“输入引擎”。它实际是一个拥有若干函数指针成员的结构体,MiniGUI在特定的时候调用这些函数来达到操作硬件的目的,因此,编写特定的输入引擎,主要就是编码实现INPUT结构中的各个函数。该结构定义在/minigui-free/libminigui-1.3.3/src/ial/ial.h中,其中的主要成员函数如表l所列。为表述方便,定义当前工作目录为/mlnlgui-free/libminigui-1.3.3,后文出现的所有文件目录及路径均在该目录下。
3.2 编写小键盘输入引擎
3.2.1 底层输入操作函数实现
对于小键盘输入,鼠标操作接口函数不用进行任何操作,直接返回即可,主要需要编写的是keyboard_update及wait_event函数。当。MiniCUI应用程序运行时,相关的底层事件处理例程会不断调用wait_event函数查询是否有输入事件发生,故在该函数中调用小键盘驱动的read函数,获取用户输入的按键信息。若有键盘事件发生,则返回IAL_KEYEVENT,底层事件处理例程就会调用keyboard_update函数进行处理,获取当前键盘状态。
需要注意的是,由于系统以很高的频率不断调用wait_event函数,因此当该函数捕捉到键按下事件时,需要一定时间(如100 ms)延时再返回,以避免一次按键产生多次键盘事件。
MiniGUI使用一个一维数组state[128]记录按键的状态。该数组定义在include/common.h中。State[128]中每个元素均对应一特定的按键,如果某一元素为l,说明它所对应的键被按下,否则该键未被按下。因此,key-board_update函数要做的工作就是,根据键盘扫描驱动程序的返回值,更新state[128]数组的元素值,从而向上层驱动程序和应用程序反映按键状态。可见,若想实现任意标准键盘按键功能,只需修改keyboard_update函数里相应的键值映射,或直接修改键盘驱动里的键值映射数组为对应的标准键盘按键的系统扫描码。
3.2.2 初始化及终止函数实现
在初始化函数中先打开小键盘输入设备,成功以后对输入引擎的其他成员(底层输入操作接口函数)赋值,返回TRUE。终止清除函数的主要工作是关闭键盘输入文件。输入引擎相关内容的格式可参照src/ial/目录下的其他输入引擎。至此,完成了小键盘输入引擎(mykbd.c文件)的开发。
3.3 输入引擎的使用原理
在src/ial/ial.c中,用inputs结构数组定义了MiniGUI支持的所有输入引擎信息。系统启动后,将根据MiniGUI.cfg配置文件,在inputs结构中寻找特定的输入引擎作为当前的输入引擎。然后,调用该引擎的初始化函数,对全局变量cur_input(表当前使用的输入引擎)的其他成员函数进行赋值。
在src/sever/server.c中,函数IdleHandler4Server凋用输入引擎中IAL_WaitEvent成员函数,检查是否有底层输入事件发生。当有事件发生时,检查是鼠标(触摸屏)事件还是键盘事件发生,并分别用parseEvent(msg_que, event)处理这些事件。parseEvent函数中首先调用Getl-wevent(event,&1we)函数。该函数利用IAL引擎中相应底层操作函数收集底层输入事件1we(该结构定义在paxseEverlt函数中),parseEvent再将收集到的这些事件转化为上层能理解的消息。具体实现细节可参考server.c文件。
4 键盘输入在MiniGuI中的实现步骤
4.1 加载小键盘驱动
有两种方法加载:一是把该驱动加载入内核;二是可以将编译的*.o文件拷贝到目标板根文件系统巾,目标板启动后用insmod命令动态加载。
4.2 添加小键盘输入引擎
添加小键盘输入引擎方法步骤如下:
①仿照src/ial/2410.h编写mykbd.h文件,与myk—bd.c文件一同保存到src/ial下;
②在src/ial/ial.c文件中添加新引擎的人口(位置及格式参考该文件中其他引擎);
③在conflgure.in、acconfig.h及src/ial/Make-fne.am文件中的其他引擎信息之后加人新引擎信息;
④执行aclocal及autoheader,分别生成aclocal_m4及config.h.in文件;
⑤执行|dLltoconI’,生成。onfigurt:,修改该con矗lgure文件,在开头处添加交叉编译器路径(否则会使用gcc进行编译);
⑥执行aLit0131~lke—add_misslng命令,生成MaItefile.in等文件;
⑦执行./configure--enable-jpgsupport=no--enaable=pngsupport=no--enable-gifsupport=no--disable-lite--prefix=
/minigui-free/install--enable-mykbdial=yes(指定安装路径在/tnlr电心free/lnstall目录下,若configure.in中设置该输入引擎默认为安装,则不用加最后一项配置参数);
⑧执行make,及rrlake,instaII命令进行编译和安装;
⑨把安装路径下的Iib/libminigui一1.3.so.3.0.O库文件复制到目标板根文件系统lIb目录下(前提是已拷贝了MiniGLfI运行库和资源环境到根文件系统中);
⑩修改配置文件(目标板根文件系统/et~:/MinigLti. cfg),令iaLenglne—mylebd,使用这个新的输入引擎。
4.3 根文件系统的移植
将交叉编译后的MiniGtII应用程序复制到根文件系统中,制作并下载根文件系统映像文件到目标板中,目标板系统启动后加载小键盘驱动并运行该应用程序即可。(源程序见本刊网站www.rllesnet.com.cn——编者注)
结语
开发MiniGIJI对特定输入设备的支持,主要完成的是输入设备驱动及输入引擎的编写、新输入引擎的添加。调试过程中,应根据串口终端的错误提示和程序运行时的现象判断是驱动程序或输入引擎编写有误,还是设有正确添加输入引擎造成了错误,再进行相应的修改。建议先用非Mini(:u1程序调试驱动程序,确保其能正确实现所提供的功能后,再运行MiniGIJI应用程序进行调试。如果出现的错误为无法找到匹配的输入设备,则多是未能正确掭加输入引擎造成;若错误为初始化输入引擎失败,则是驱动未成功加载或输入引擎初始化函数中打开的设备名与驱动注册的设备名不符合造成的。本文所述的方法,已经在嵌入式血液流变仪的数字键盘输入应用中成功使用。实际使用结果表明,键盘输人程序行为正确,对按键反应速度快,可靠性高。