6人机交互接口设计.docx
《6人机交互接口设计.docx》由会员分享,可在线阅读,更多相关《6人机交互接口设计.docx(38页珍藏版)》请在冰豆网上搜索。
6人机交互接口设计
6人机交互接口设计158
6.1键盘输入接口158
6.1.1键盘工作原理158
6.1.2常用键盘接口159
6.1.3键盘驱动程序实例161
6.2LCD显示接口162
6.2.1LCD简介163
6.2.2在嵌入式Linux中驱动LCD164
6.2.3LCD接口电路167
1.S3C4510BLCD显示接口电路167
2.S3C44B0X与LCD显示模块的接口168
6.2.4uClinux下开发LCD应用程序169
6.3触摸屏交互接口171
6.3.1触摸屏的基本原理171
6.3.2触摸屏的输入系统173
6.3.3S3C44B0X触摸屏应用程序举例173
6人机交互接口设计
人机交互接口,是计算机和人机交互设备之间的交接界面,通过接口可以实现计算机与外设之间的信息交换。
人机交互设备是计算机系统中最基本的设备之一,是人和计算机之间建立联系、交换信息的外部设备,常见的人机交互设备可分为输入设备和输出设备两类。
人机接口是计算机同人机交互设备之间实现信息传输的控制电路。
接口中要分别传送数据信息、命令信息和状态信息。
数据信息、命令信息和状态信息都通过数据总线来传送。
大多数计算机都把外设的状态信息视为输入数据,而把命令信息看成输出数据,并在接口中分设各自相应的寄存器,赋以不同的端口地址,各种信息分时地使用数据总线传送到各自的寄存器中去。
在嵌入式系统中,目前常见的人机接口设备有键盘、LCD、触摸屏等。
6.1键盘输入接口
在ARM嵌入式系统应用中,键盘是人机交互对话最通用的方法之一。
操作者通过键盘向系统发送各种指令或置入必要的数据信息。
键盘模块设计的好坏,直接关系到系统的可靠性和稳定性。
在ARM应用系统中,键盘扫描只是ARM的工作内容之一,ARM在忙于各项工作任务的同时,如何兼顾键盘的输入,则取决于键盘的工作方式。
键盘工作方式的选取原则是既要保证能及时响应按键操作,又要不过多占用ARM的工作时间。
6.1.1键盘工作原理
通常的标准键盘是由许多按键开关组成的。
按键开关电路是指通过外力使电路瞬时接通的开关,在许多场合都有应用。
比如大多数处理器的RESET电路都用到了按键开关,它通过按键产生一个瞬时的低电压,CPU感知这个低电压后重启。
在有些系统中也用按键开关切换工作模式,它通过按键开关生成一个低压脉冲,产生一次中断,在中断处理程序中改变工作模式,并且通过置外部标志的方式告知用户当前的工作模式,通过切换开关,就可以实现在不同工作模式之间进行切换。
按键开关的电路如图6.1所示。
图6.1按键开关电路示意图
当按键断开时,输出高电压,为逻辑1;当按键按下时,电平输出点与地相连,输出低电平,为逻辑0。
如图6.1所示的按键开关电路是最简单的,遗憾的是,它并不完善,因为它按下或者被释放时,并不能明确地产生一个逻辑0或者逻辑1。
由于按键是机械触点,当机械触点断开、闭合时,会产生抖动。
这种抖动对于用户来说是感觉不到的,但对计算机来说,则是完全可以感应的。
计算机处理的速度是在微秒级,而机械抖动的时间至少是毫秒级,这对计算机而言,已是一个“漫长”的时间了。
假如利用按键开关产生中断可能就会产生一个问题,就是说按键有时灵,有时不灵,其实就是这个原因。
有可能只按了一次按键,可是计算机却已执行了多次中断的操作。
为使CPU能正确地读出按键的状态,对每一次按键只作一次响应,就必须考虑如何去除抖动。
常用的去除抖动方法有软件方式和硬件方式两种。
对于简单的按键电路,可以采用软件方法去除抖动。
软件方法其实很简单,就是在程序获得外接端口为低的信息后,不是立即认定按键已被按下,而是延时10毫秒或者更长一段时间后再次检测外部端口,如果仍为低,说明按键的确按下了,这实际上是避开了按键按下时的抖动时间。
同理,在检测到按键释放后再延时5~10毫秒,消除后沿的抖动,然后再对键值处理。
实践证明,不对按键释放的后沿进行处理,通常也能满足一定的要求。
但有时用软件方式并不能很好地解决按键抖动问题,例如按键开关连接的是中断请求线,程序是不能读取中断请求线的状态的,这时就需要使用硬件方法。
硬件方法其实就是一个去除抖动电路,用于去除按下和释放按键时的波形抖动,这个电路也是比较简单的,读者可以查找相关去抖电路。
对于比较复杂的矩阵键盘而言,通常使用专用芯片去除抖动,例如键盘接口芯片8279、MAX6816、MAX6817、MAX6818等。
6.1.2常用键盘接口
常用按键接口可分为独立式按键接口、行列式按键接口和专用芯片式按键接口等。
具体采用哪种方式,可根据所设计系统的实际情况而定。
下面分别介绍这几种接口方式的优缺点及适用场合。
1.独立式按键接口
独立式按键接口设计优点是电路配置灵活,软件实现简单。
但缺点也很明显,每个按键需要占用一根口线,若按键数量较多,资源浪费将比较严重,电路结构也变得复杂。
因此本方法主要用于按键较少或对操作速度要求较高的场合。
软件实现时,可以采用中断方式,也可以采用查询方式,如图6.2所示。
图6.2独立式键盘接口
2.行列式按键接口
行列式按键接口如图6.3所示,其使用原理将在下节详细讲述。
行列式按键接口适用于按键数量较多,又不方便使用专用键盘芯片的场合。
这种方式的按键接口由行线和列线组成,按键位于行、列的交叉点上。
这种方式的优点就是相对于独立接口方式可以节省很多I/O资源,相对于专用芯片键盘可以节省成本,且更为灵活。
缺点就是需要用软件处理消抖、重键等。
行列式按键接口是一种老式的键盘接口,其按键扫描方法是几乎所有PC键盘所采用的方法。
如何确定行列式键盘上哪个键被按下,这里介绍一种“行扫描法”。
行扫描法又称为逐行(或列)扫描查询法,是一种最常用的按键识别方法。
扫描过程分为以下两步。
(1)判断键盘中有无键按下。
将全部行线置低电平,然后检测列线的状态。
只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平与4根行线相交叉的4个按键中。
若所有列线
图6.3行列式键盘接口
均为高电平,则键盘中无键按下。
(2)判断闭合键所在的位置。
在确认有键被按下后,即可进入确定具体闭合键的过程。
其方法是:
依次将行线置为低电平,即在某根行线为低电平时,把其他行线置为高电平。
在确定某根行线位置为低电平后,再逐行检测各列线的电平状态。
若某列为低,则该列线与置为低电平的行线交叉处的按键即为闭合按键。
例如在图6.3中,CPU的低8位用作键盘I/O口,其中,键盘的列线连接到I/O口的低4位,键盘的行线连接到I/O口的高4位。
列线B0~B3分别连接有4个上拉电阻到正电源+5V,并把列线设置为输入线,行线B4~B7设置为输出线,4根行线和4根列线形成16个相交点。
如果进行键盘扫描,再加上去除抖动的功能,要执行如下操作:
(1)检测当前是否有按键被按下。
检测的方法是B4~B7输出全“0”,读取B0~B3的状态,若B0~B3全为“1”,则无键闭合,否则为0的那一列有键闭合。
(2)去除键抖动。
当检测到有键按下后,延时一段时间再作下一步的检测判断。
(3)若有键被按下,应识别出是哪一个键闭合。
方法是对键盘的行线进行扫描。
B4~B7按下述4种组合依次输出:
P71110
P61101
P51011
P40111
(4)在每组行输出时读取P0~P3,若全为“1”,则表示设为“0”的这一行没有键闭合,否则有键闭合。
由此得到闭合键的行值和列值,通常是一个扫描码,然后可采用计算法或查表法将闭合键的行值和列值转换成所定义的键值。
为了保证键每闭合一次CPU仅作一次处理,必须去除按键释放时的抖动。
通过以上步骤就可以得到被按下键的扫描码了,通常把扫描码放到一个缓冲区内,直到应用程序处理按键为止。
缓冲是一个很有用的措施,因为当应用程序出现按键状态改变却不能及时处理的情况时,通过缓冲区就可以防止按键的丢失。
缓冲区的大小取决于应用程序的需要,一般应该大于10。
一般来说,都是把缓冲区作为一个环行队列来管理。
使用两个指针,一个指向第一个空位,一个指向第一个扫描码。
当一个按键被按下时,扫描码将被放置在环形队列的空指针指向的位置。
而应用程序则是通过指向第一个扫描码的指针去读取扫描码。
若缓冲区已满,则任何下一个按键都将被丢弃
3.专用芯片式按键接口
专用键盘处理芯片一般功能比较完善,芯片本身能完成对按键的编码、扫描、消抖和重键等问题的处理,甚至还集成了显示接口功能。
专用键盘处理芯片的优点很明显,可靠性高,接口简单,使用方便,适合处理按键较多的情况。
但在很多应用场合,考虑成本因素,可能并不是最佳选择。
6.1.3键盘驱动程序实例
在前面部分已经对如何在一个嵌入式系统中扩展小键盘及相关电路连接进行了说明。
在嵌入式系统的软件部分,要做的就是把前面的硬件电路驱动起来,为它们写一个驱动程序,下面就以一个实例进行说明如何编写键盘驱动程序。
键盘作为Linux默认输入设备,一般嵌入式Linux操作系统都带有标准键盘的驱动程序。
键盘是一个字符设备,它的驱动程序为drivers/char/keyboard.c,其对应的头文件为keyboard.h。
在Intel构架中,键盘把自己固定在IRQ1上,键盘状态的寄存器地址为0x64h,键盘扫描码的寄存器地址为0x60h。
当用户按下按键后,将产生中断,在中断处理程序中,将读出键盘状态和键盘扫描码,然后把键盘扫描码通过对应表转换为ASCII码,送往用户应用程序。
本节的实例也是针对Intelx86体系结构。
参照标准键盘的驱动程序,这个实例也使用IRQ1中断,从0x64h读入键盘状态,从0x60h读入键盘扫描码,这样就跟系统自带的键盘驱动程序发生冲突了,这时的新添程序是无法捕捉按键中断的。
由于系统自带的驱动程序和要写的驱动代码不能共存,所以首先必须使系统自带的键盘驱动释放中断。
但因为在内核源文件(drivers/char/keyboard.c)里它是作为一个静态符号被定义的,所以没有办法恢复它,只能重新启动,才能恢复原来的中断。
本节这段代码是把它自动绑定到IRQ1上,在Intel结构下这是键盘控制的IRQ。
这时,当它连接到一个键盘中断时,将读出键盘的状态(这是inb(0x64)的目的)和由键盘返回的扫描码。
随后只要内核认为可以时,它将运行got_char给出键的编码(扫描码的前7位)和是否被按下的信息(如果第8位是0则表示按下,是1表示释放)。
下面是键盘驱动实例代码。
//************************************************
//键盘驱动范例keybd.c
//必要头文件
//标准头文件
//************************************************
#include//内核工作
#include//明确指定是模块
#ifCONFIG_MODVERSIONS==1//处理CONFIG_MODVERSIONS
#defineMODVERSIONS
#include
#endif
#include
#include
#include//在程序中将用到中断
#include
//在2.2.3版/usr/include/linux/version.h中包含这个宏,但2.0.35版不包含,因此在这加入//以备需要
#ifndefKERNEL_VERSION
#defineKERNEL_VERSION(a,b,c)((a)*65536+(b)*256+(c))
#endif
//BottomHalf—一旦内核模块认为它做任何事都是安全的时候这将被内核调用
staticvoidgot_char(void*scancode)
{
printk(“ScanCode%x%s.\n”,
(int)*((char*)scancode)&0x7F,
*((char*)scancode)&0x80?
“Released”:
“Pressed”);
}
//这个函数为键盘中断服务。
它读取来自键盘的相关信息,然后安排到当内核认为bottomhalf
//安全的时候让它运行
voidirq_handler(intirq,void*dev_id,structpt_regs*regs)
{
//这些变量是静态的,因为它们需要对bottomhalf可见(通过指针)
staticunsignedcharscancode;
staticstructtq_structtask=
{NULL,0,got_char,&scancode};
unsignedcharstatus;
status=inb(0x64);//读取键盘状态
scancode=inb(0x60);//读取扫描码
#ifLINUX_VERSION_CODE>KERNEL_VERSION(2,2,0)//安排bottomhalf运行
queue_task(&task,&tq_immediate);
#else
queue_task_irq(&task,&tq_immediate);
#endif
mark_bh(IMMEDIATE_BH);
}
//在这里假设驱动的加载还是采用模块化方式
//初始化模块—登记IRQ句柄
intinit_module()
{
//由于原来键盘的句柄不能和本驱动程序共存,所以在启动本程序前不得不关闭它(释放它的
//IRQ)。
同时因为不知道它在哪儿,所以抢占以后没有办法恢复它,因此当本程序运行完后计
//算机将被重新启动
free_irq(1,NULL);
//请求IRQ1,键盘的IRQ,指向我们的irq_handler
returnrequest_irq(1, //PC上的键盘的IRQ号
irq_handler, //我们的句柄
SA_SHIRQ,//SA_SHIRQ意味着将这个IRQ指定为可以共享
//SA_INTERRUPT能使句柄为一个快速中断
“test_keyboard_irq_handler”,NULL);
}
voidcleanup_module()//清除
{
//这段代码在此只是为了使驱动程序结构完整。
它是完全不相关的,因为没有办法恢复被屏蔽
//的系统自带键盘中断,因此计算机完全没用了,需要被重新启动
free_irq(1,NULL);
}
6.2LCD显示接口
在ARM嵌入式系统中,人机接口不但包括可以输入的键盘,还有用于传送信息给用户的输出设备。
液晶显示器LCD具有显示信息多、质量高、无电磁辐射、可视面积大、应用范围广、画面效果好、数字式接口、体积小、功耗低等特点,在基于微处理器的嵌入式系统终端显示、人机接口中受到普遍欢迎,极大地提高了嵌入式系统的易用性和操作的直观性。
本节将主要介绍LCD显示原理、LCD分类及LCD驱动程序。
6.2.1LCD简介
1.显示原理
液晶显示器的显像原理,是将液晶置于两片导电玻璃之间,靠两个电极间电场的驱动,引起液晶分子扭曲向列的电场效应,以控制光源透射或遮蔽功能,在电源开/关之间产生明暗而将影像显示出来。
若加上彩色滤光片,则可显示彩色影像。
在两片玻璃基板上装有配向膜,所以液晶会沿着沟槽配向。
由于玻璃基板配向膜沟槽偏离90°,所以液晶分子成为扭转型,当玻璃基板没有加入电场时,光线透过偏光板跟着液晶作90°扭转,透过下方偏光板,液晶面板显示白色;当玻璃基板加入电场时,液晶分子产生配列变化,光线通过液晶分子空隙维持原方向,被下方偏光板遮蔽,光线被吸收无法透出,液晶面板显示黑色。
液晶显示器便是根据此电压有无,使面板达到显示效果。
2.LCD显示器的分类
按显示功能的强弱分类,LCD可分为段位式LCD、字符式LCD和点阵式LCD。
其中,段位式LCD和字符式LCD只能用于字符和数字的简单显示,不能满足图形、曲线和汉字显示的要求。
而点阵式LCD不仅可以显示字符、数字,还可以显示各种图形、曲线和汉字,并且可以实现屏幕上下左右滚动、动画、分区开窗口、反转、闪烁等功能,用途十分广泛。
按照液晶显示器的使用场合,其采用的显示模块还可以分为数显液晶模块、点阵式液晶字符模块、点阵图型液晶模块。
下面将分别对这3类显示模块加以介绍。
(1)数显液晶模块
数显液晶模块是一种由段式液晶显示器件与专用的集成电路组装成一体的功能部件,只能显示数字和一些标识符号。
段式液晶显示器件大多应用在便携、袖珍设备上。
由于这类设备体积小,所以尽可能不将显示部分设计成单独的部件。
即使一些应用领域需要单独的显示组件,也应该使其除具有显示功能外,还应具有一些信息接收、处理、存储传递等功能。
由于它们具有某些通用的、特定的功能,而广受市场的欢迎。
常见的数显液晶显示模块具有计数、计时、计量等功能。
(2)点阵式液晶字符模块
点阵式液晶字符模块是由点阵式液晶显示器件和专用的行、列驱动器,控制器以及必要的连接器件装配而成的。
它可以显示数字和西文字符。
这种点阵式字符模块有的本身带有字库,有字符发生器,具有显示容量大、功能丰富的特点。
一般这种模块最少也可以显示8位1行或者16位1行以上的字符。
这种模块的点阵排列是有8×8、16×8或16×16的一组一组像素点阵排列组成的。
每组的像素组成1个字,每个字之间有一定的间隔,每行字之间也有一行的间隔,所以不能显示图形。
一般在模块控制、驱动器内不仅具有已固化好字符字模的字符库CGROM,还具有让用户自定义建立专用字符的随机存储器CGRAM,它允许用户建立自己的点阵字符。
(3)点阵式图形液晶模块
点阵图形液晶模块也是点阵模块的一种,其特点是点阵像素连续排列,行和列在排布中均没有空隔,因此可以显示连续、完整的图形。
由于它也是由X-Y矩阵像素构成的,所以除显示图形外,也可以显示字符。
它又可以分为以下几类:
1)行、列驱动型
行、列驱动型是一种必须外接专用控制器的模块,其模块只装配有通用的行、列驱动器,这种驱动器实际上只有对像素的一般驱动输出端,而输入端一般只有4位以下的数据输入端、移位信号输入端、锁存输入端、交流信号输入端等,如HD44100、IID66100等。
此种模块必须外接控制电路,如HD61830、SED1330等才能与计算机连接。
该种模块数量最多,应用最普遍。
虽然需要采用自配控制器,但它也给客户留下了可以自行选择不同控制器的自由。
2)行、列控制型
行列控制型是一种可直接与计算机接口,依靠计算机直接控制驱动器的模块。
这类模块所用的列驱动器具有I/O总线数据接口,可以将模块直接挂在计算机的总线上,省去了专用控制器,因此对整机系统降低成本有很大的好处。
对于显示系统的像素数量不大,整机功能不是很复杂的系统非常适用,不过它会占用系统的部分资源。
3)行列驱动—控制型
行列驱动—控制型是一种内藏控制器的点阵图形模块,也是比较受欢迎的一种类型。
这种模块不仅装有如第一类的行、列驱动器,而且也装配有如T6963C等的专用控制器。
这种控制器是液晶驱动器与计算机的接口,它以最简单的方式受控于计算机,接收并反馈计算机的各种信息,经过自己独立的信息处理实现对显示缓冲区的管理,并向驱动器提供所需要的各种信号、脉冲,操纵驱动器实现模块的显示功能。
这种控制器具有自己的一套专用指令,并具有自己的字符发生器CGROM,这就要求用户必须熟悉这种控制器的详细说明书,才能进行操作。
这种模块使用户摆脱了对控制器的设计、加工、制作等一系列工作,又使计算机避免了对显示器的繁琐控制,节约了主机系统的内部资源。
3.显示汉字
一般西文为8×8点阵,因而显示一个西文字符只需要8个字节,而每一个汉字要占4个西文字体,因此显示一个汉字需要32个字节。
汉字字库表为一张数据表,每个汉字在数据表中通常由32个字节组成一个点阵图形。
在应用时,连续取32个字节送到LCD的相应位置,就能正确显示汉字后的图形符号。
在嵌入式系统中,如果需要显示的汉字是固定的,并且字数较少,可以直接在软件的头文件中定义汉字的显示点阵表格,要显示时,直接从表格变量数组中连续取出32个汉字送往LCD显示器即可。
但是如果要显示的汉字字数很多,或者又不能确定要显示哪些汉字时,使用上述办法就相当麻烦了。
这时应当使用汉字字库。
有些LCD驱动器自带汉字字库,如果没有带,可以自己使用ROM扩展,通过把汉字机内码送往字库文件,得到对应的显示点阵。
6.2.2在嵌入式Linux中驱动LCD
随着应用需求的推动,嵌入式Linux操作系统下也出现了许多图形界面软件包,如MiniGUI、Trolletech公司的EmbeddedQT等。
这些图形界面开发包与WinCE相似,在图形软件包的开发和移植工作中都牵涉到底层LCD驱动的问题。
在本节中将介绍有关在嵌入式Linux下实现LCD驱动的相关知识。
Linux的设备管理是和文件系统紧密相关的,各种设备都以文件的形式存储在/dev目录下,称为设备文件。
应用程序可以打开、关闭、读写这些设备文件,完成对设备的操作,就像对普通数据文件操作一样。
另外,Linux把它所管理的设备分为字符设备和块设备,它们的区别在于系统为块设备提供了缓冲机制。
由于设计缓冲区的管理、调度和同步等问题,块设备的驱动要比字符设备复杂。
Linux把显示驱动也看作字符设备,把要显示的数据一个字节一个字节地送往LCD驱动器。
Linux为所有的设备文件都提供了统一的操作函数接口,方法是使用数据结构structfile_operations,这个数据结构中包括许多操作函数的指针,如open()、close()、read()、write()等。
但是,由于外设的种类繁多,操作方式也不一样,如声音设备驱动要使用DMA通道、显示设备要提供对显存的操作、硬盘驱动要处理复杂的缓冲区结构等。
如果file_operations中的函数都是用驱动开发人员来编写实现,其工作量相当大,而且对于每一类设备,它的许多操作也是相似的,许多数据结构也是可以公用的。
为了解决这个问题,Linux采用了更高一层的封装方法,为同一类设备定义好了文件层次的file_operations结构中的接口函数,在其中处理了大多数设备相关的操作,如各种缓冲区的申请和释放等。
而具体操作底层硬件的一小部分则留给驱动开发人员去实现,这样就大大减少了驱动程序开发的难度。
所以Linux提供了另外一个文件层到底层驱动的接口,通常为一个结构体,其中包含成员变量和函数指针等,不同的设备驱动有着不同的数据结构。
这样,一方面保证了文件层I/O接口file_operations的一致性;另一方面,驱动程序的开发人员也不用了解设备驱动太多的细节,只需专注于硬件相关的I/O操作即可。
例如,一个具有代表性的声音设备,其文件层的file_operations定义如下。
structfile_operationsoss_sound_fops=
{
owner:
THIS_MODULE,
llseek:
sound_lseek,
read:
sound_read,
write:
sound_write,
poll:
sound_poll,
ioctl:
soun