摘要:本文讨论了7×3矩阵键盘的工作原理和Windows CE操作系统的矩阵键盘驱动程序模型,详细分析和阐述了嵌入式系统中手机键盘驱动程序的设计和实现方法。
关键词:矩阵键盘、Windows CE、MDD、PDD、驱动程序
1. 前言
矩阵键盘是嵌入式设备中常用的输入设备。它具有坚固耐用、响应速度快、小巧方便、原理简单、价格便宜、易于交流等诸多优点。利用矩阵键盘,用户只要用手指按下键盘上的数字或符号键就能实现对嵌入式设备进行相应的操作,从而使人机交互更为直接,是极方便的交互设备。矩阵键盘的应用范围非常广泛,特别是在手机、PDA等手持产品的运用更为广泛。本文讨论了矩阵键盘的实现原理和Windows CE操作系统的矩阵键盘驱动程序模型,并详细阐述和分析了嵌入式系统中矩阵键盘驱动程序的设计和实现方法,对开发手机键盘具有重要的参考价值。
2. 矩阵键盘原理
矩阵键盘作为输入设备以默认每秒2次的频率扫描键盘,当有按键被按下时,通过扫描键盘并生成相应的扫描码,并通过处理器中的中断产生器产生一个中断信号,然后通过这个中断信号控制相应的程序获取与之相对应的虚拟码,最后此虚拟码由上层调用,实现按下此键的相应功能。
键盘配置是很关键的,其中包括按键的个数、布局及按键功能的配置。键盘可以按照自定义布局,并且可以按照自己的喜好映射按键,从而实现按键的不同功能;对于Intel PXA272芯片而言,最多支持8×8的矩阵键盘,这个矩阵键盘接口连接PXA272处理器到矩阵键盘上,本次开发只使用7×3的矩阵键盘,键盘布局按照常用手机键盘布局,其中Intel PXA272芯片的GPIO107、GPIO108、GPIO96分别对应矩阵键盘的输出端口4~6,Intel PXA272芯片的GPIO100、GPIO101、GPIO102、GPIO97、GPIO39、GPIO90、GPIO91分别对应矩阵键盘的输入端口0~6。矩阵键盘原理详见下图1所示[1]。
图1 矩阵键盘原理图
3. 键盘接口I/O信号描述
KP_MKIN<7:0>信号为来自矩阵键盘的输入信号和矩阵行所读取的信号。
KP_MKOUT<7:0>为矩阵键盘的输出信号。这个键盘接口发射扫描信号到矩阵键盘的每一列,并检查是否有键被按下。
4. 矩阵键盘驱动程序模型
分层驱动程序由两个独立的层组成:上层是模型设备驱动程序(MDD),映射扫描码到虚拟键的编码上,产生与虚拟键编码相关的字符,然后打包键盘信息,并且将此信息输入到系统信息队列中;下层是依赖平台的驱动程序(PDD),它将从硬件重新获得扫描码。设备驱动程序服务器提供的接口(DDSI)是在PDD中实现的函数集,并由MDD调用。由于微软提供了所有与MDD模块相关的源代码,所以对这部分不用做任何改动,只需将自己的PDD模块与MDD模块链结成一个公用库即可。下图2是矩阵键盘驱动程序分层结构模型[2]、[3]:
图2矩阵键盘驱动程序分层结构模型
DDI函数在MDD层实现,由用户应用程序通过GWES子系统调用,键盘驱动的DDI函数有[4]:KeybdDriverGetInfo、KeybdDriverSetMode、KeybdDriverPowerHandler、KeybdDriverInitializeEx、KeybdDriverInitStates、KeybdDriverVKeyToUnicode、KeybdDriverMapVirtualKey。
DDSI函数在PDD层实现,由MDD层调用,键盘驱动的DDSI函数有:KeybdPdd_PowerHandler、KeybdPdd_InitializeDriverEx、KeybdPdd_GetEventEx、DllMain。
5. 矩阵键盘驱动程序运行过程
Windows CE的输入系统在启动时加载矩阵键盘驱动程序,其加载流程如下:当输入系统开始运行时,输入系统将从HKEY_LOCAL_MACHINE\Hardware\DeviceMap\KEYBD\Drivername注册键中获取矩阵键盘驱动动态链接库(DLL)的名字。如果没有找到入口函数,系统将使用默认名字Keybddr.dll,然后加载这个DLL文件,并且确认所需要的条目指针是否都存在;然后,系统调用PFN_KEYBD_DRIVER_INITIALIZE 函数去执行一次初始化工作。在这个函数中,模型设备驱动程序(MDD)存储一个输入系统回调函数的拷贝,并且处理键盘中断的中断服务线程(IST)。当一个中断信号发出时,键盘驱动将与转变硬件扫描码为虚拟按键码有关,并且与回调PFN_KEYBD_DRIVER_INITIALIZE_EX函数和keybd_event API 有关[3]。
在CAYMAN开发板中,键盘驱动的动态链接库名字为KeyPad.dll,入口点为DllMain。通过入口函数,调用KPControl::Initialize函数完成键盘时钟、相关GPIO口和键盘中断的一次性初始化。MDD还调用KeyPdd_InitializeDriverEx函数,该函数启动一个线程处理键盘中断,然后返回到输入系统。
在CAYMAN开发板中,键盘驱动程序的中断服务线程(IST)的名字是m_hevInterrupt。这个线程调用函数InterruptInitialize注册SYSINTR_KEYBOARD中断,然后等待系统发出SYSINTR_KEYBOARD信号。系统在收到中断信号后,中断处理程序调用KeypdPdd_GetEventEx函数来获取按键的扫描码,然后调用ScanCodeToVKeyEx函数将扫描码映射成虚拟码。把从PDD返回的键盘事件发送到输入系统,输入系统对它们进行排队并分发给相应的应用程序。
6. KeypdPdd_GetEventEx函数
当输入系统载入矩阵键盘驱动后,由矩阵键盘驱动执行一系列初始化工作,然后开启一个线程进入键盘中断主循环,等待键盘事件的发生。一旦发生键盘事件,即检测到有按键被按下,立即调用KeypdPdd_GetEventEx函数来获取按键的扫描码。
其中,列为矩阵扫描输入端,行为矩阵键盘输出端,当有按键被按下时,矩阵键盘的相应行和列所对应的输入输出电平将相应地发生变化,通过矩阵键盘的扫描,将此值存储于键盘接口自动扫描寄存器的相应位中,然后将此数据进行如下操作:
1) 屏蔽键盘自动扫描寄存器的列数据的值,将此值存储于C中。
1) 屏蔽键盘自动扫描寄存器的行数据的值,将此值存储于R中。
2) 将上面两步产生的数据进行或运算,所得的数据就是被按下键的扫描码。
对于7×3的矩阵键盘,下图为物理按键和扫描码的对应关系(扫描码为16进制):
7. ScanCodeToVKeyEx函数
此函数提供扫描码到虚拟键的映射操作,主要调用MapVkeyFromSCode函数完成从扫描码到虚拟按键的映射。在MapVkeyFromSCode函数的实现过程中,首先需要按照自己的要求和物理键盘的布局确定SC2VKMap[i][j]二维数组,其中数组的第一列为物理键盘上每个按键所对应的扫描码,第二列为第一列扫描码所对应的虚拟按键,开发者可以根据实际需要确定扫描码和虚拟按键的对应关系,通过这个二维数组的设定,就可以在程序运行的过程中,当检测到有按键被按下时,通过KeypdPdd_GetEventEx函数产生的扫描码,然后通过查表的方式得到扫描码所对应的虚拟按键值。下表为扫描码与虚拟码的对应关系表:
其中VK_A、VK_B、VK_C、VK_D、VK_E、VK_F、VK_G、VK_H、VK_I、VK_J、VK_K、VK_1、VK_2、VK_3、VK_4、VK_5、VK_6、VK_7、VK_8、VK_9、VK_0对应的输出为A、B、C、D 、E、F、G、H、I、J、K、1、2、3、4、5、6、7、8、9、0,但实际显示的时候可以按照具体的要求进行定义,完成物理按键对应的输出值,每个按键所实现的功能是由上层应用程序定义的,这里再不详细叙述。
8. KeyPadGpioConfigure函数
此函数的功能是完成矩阵键盘所对应GPIO口的配置,在具体函数的实现和开发中必须按照物理键盘的布局及芯片引脚占用情况进行相应的更改的。下面为KeyPadGpioConfigure函数的实现:
XLLP_UINT32_T GpioDirOutList[]={3,107,108,96, }; //矩阵键盘3个输出端口引脚号
XLLP_UINT32_T GpioDirInList[]={7,100,101,102,97,39,90,91}; //矩阵键盘7个输出端口引脚号XLLP_UINT32_T GpioAltFnPinList[]={10,39,90,91,96,97,100,101,102,107,108};//矩阵键盘GPIO引脚XLLP_UINT32_T GpioAltFnValList[]={10,1,1,1,3,1,1,1,1,2,2}; // GPIO对应的附加功能选择
if(v_pGPIOReg != 0) //判断键盘GPIO寄存器是否已经被配置
{
XllpGpioSetDirectionIn(v_pGPIOReg, GpioDirInList); //设置GPIO输入端口方向
XllpGpioSetDirectionOut(v_pGPIOReg, GpioDirOutList); //设置GPIO输出端口方向
XllpGpioSetOutput0(v_pGPIOReg, GpioDirOutList); //设置GPIO输出端口
XllpGpioSetAlternateFn(v_pGPIOReg, GpioAltFnPinList, GpioAltFnValList); //设置GPIO附加功能
}
if(v_pKeyPadRegs != 0) //判断键盘寄存器是否已经被配置
{
v_pKeyPadRegs->kpControlReg=(MATRIX_KP_NUMBER_OF_ROWS| MATRIX_KP_NUMBER_OF_COLUMNS | MAT_SCAN_LINE4 | MAT_SCAN_LINE5 | MAT_SCAN_LINE6 | AUTO_SCAN_ON_ACTIVITY | MATRIX_INTR_ENABLE | MATRIX_KP_ENABLE ) ; //设置矩阵键盘控制寄存器初值
retval = XLLP_TRUE;
}
return(retval);
9. 结束语
本文作者创新点:完整地分析了Windows CE操作系统中7×3矩阵键盘的基本原理及其驱动程序模型,此设计是按照目前通用的手机键盘开发。并从实现方法的角度深入剖析了Windows CE中矩阵键盘扫描码的获取流程、将扫描码映射到虚拟码的方法,最后给出了矩阵键盘所对应GPIO口的配置方法,对于类似系统的矩阵键盘驱动开发具有重要的参考价值。
参考文献
[1] 阿兰特嵌入式实验室.PXA27x处理器开发手册,2005:825-826.
[2] 杨翠娥,王丽敏,王景敏.实时系统VxWorks下设备驱动程序的编写[J].微计算机信息2004年第一期
[3] 傅曦.Windows CE 嵌入式开发入门——基于Xscale架构[M] 北京.人民邮电出版社,2006 :227-230.
[4] 微软.Platform Builder帮助文档.
[5] Windows CE设备驱动程序开发指南:15-16.