基于嵌入式Linux的矩阵键盘驱动程序研究与开发
2009-05-12杨斌斌张雪英王玉宏
杨斌斌 张雪英 王玉宏
摘 要:主要介绍基于嵌入式Linux的矩阵键盘驱动程序设计的方法,硬件平台基于TI提供的OMAP5912构建的嵌入式语音识别系统,充分利用OMAP5912的外围硬件资源,矩阵键盘作为平台设备和输入设备,利用Linux内核提供的输入子系统。输入子系统为输入设备驱动开发提供了良好的接口,提高了驱动程序的开发效率。驱动开发完成后,在MiniGui和Qtopia下测试,结果证明驱动程序工作高效、稳定。
关键词:矩阵键盘;嵌入式Linux;OMAP5912;设备驱动
中图分类号:TP334.2文献标识码:B
文章编号:1004 373X(2009)02 039 03
Research and Development of Matrix Keyboard Device Driver Based on Embedded Linux
YANG Binbin,ZHANG Xueying,WANG Yuhong
(College of Information Engineering,Taiyuan University of Technology,Taiyuan,030024,China)
Abstract:This paper mainly introduces a scheme of matrix keyboard device driver based on embedded Linux.The hardware platform is the embedded speech recognition system based on OMAP5912.Taking full advantage of the peripheral equipments of OMAP5912,the matrix keyboard is treated as platform device and input device.The Linux kernel offers input subsystem which provides interface to the developer and improves efficiency of the driver development.After the development of device driver is achieved,it is tested via MiniGui and Qtopia and the result proves that the device driver is effective and stable.
Keywords:matrix keyboard;embedded Linux;OMAP5912;device driver
0 引 言
随着以计算机技术、通信技术和软件技术为核心的信息技术的发展,嵌入式系统在各个行业中得到了广泛的应用。嵌入式系统已成为当今IT行业的焦点之一。而在嵌入式系统中,键盘是重要的人机交互设备之一。嵌入式Linux是一种开放源码、软实时、多任务的操作系统,是开发嵌入式产品的优秀操作系统平台,是在标准Linux基础上针对嵌入式系统进行优化和裁剪后形成的,因此具有Linux的基本性质。在此提出的矩阵键盘驱动程序的设计方案是以嵌入式Linux和TI OMAP5912处理器为软硬件平台的,在设计的嵌入式语音识别应用平台中,通过测试,表明其具有良好的稳定性和实时性。
1 硬件原理
OMAP5912处理器是由TI应用最为广泛的TMS320C55X DSP内核与低功耗、增强型ARM926EJ-S微处理器组成的双核应用处理器[1]。用这样一种组合方式将2个处理器整合在1个芯片后,开发人员可以根据实际情况,利用 DSP 运行复杂度较高的数字信号处理任务,利用 ARM 运行通信、控制和人机接口方面的任务,从而使便携式设备在保持良好人机交互环境的基础上,有效地降低功耗[2]。在外设方面,OMAP5912微处理器支持常用的各种接口,其中通过MPUIO接口最多可支持8×8的矩阵键盘,系统中采用这个接口扩展了一个4×5的矩阵键盘[3]。其硬件连接示意图如图1所示,其中按键行阵列必须提供上拉信号,列阵列加二极管,防止瞬间电流过大对MPUIO口造成冲击。
按照键盘的构造方式人们把键盘划分为线性键盘和矩阵键盘[4]。其中,线性键盘是指每个按键都占用嵌入式处理器的1个I/O端口,并通过这个I/O端口实现人机交互,各个按键之间互不影响。使用这种方案的优点是简单、可靠,但是线性键盘对I/O端口的占用量很大。因此,嵌入式系统中很少采用这种方法。
另外一种矩阵键盘是指当按键数量过多时,采用矩阵的排列方法,将按键设计成n行m列的矩阵形式。其中,每个按键占用行和列的1个交叉点,并且以行和列为单位引出信号线。这样只需要占用n+m个I/O端口,却可以驱动n×m个按键,大大节省了对嵌入式处理器I/O端口的占用,节省了宝贵的资源。矩阵键盘在减少嵌入式处理器I/O端口占用的问题上做出了很大的贡献,但随之而来的问题是如何确定矩阵中按键的位置,这里采用列扫描法,其思路如下:
在键盘初始化阶段,所有的列信号(KBC)都被设置输出为低电平。如果矩阵键盘中的1个按键按下,则相应的行信号和列信号线短路,行信号线(KBR)输入由高电平变为低电平,产生1个中断,然后在驱动的中断服务程序中按照表1中的序列逐列扫描列信号,读取行信号的状态,根据读回来的行信号状态就可以判断有那些按键按下[3]。
另外,键盘驱动必须解决的一个问题是键盘的抖动[4]。在按键按下和抬起的过程中,电压信号会出现很多毛刺,这主要是由于机械按键的弹性作用引起的。尽管触点看起来非常稳定,而且快速地闭合,但相对于嵌入式处理器的运行速度来说,这种动作是比较慢的。这种脉冲在某些按键功能设计时,如果处理不当可能会带来灾难性的后果。所以必须对按键信号进行防抖检测。
按键防抖检测的核心思想是在嵌入式处理器的几个时钟周期内,通过对按键信号进行多次访问,查看电平状态是否保存一致[5]。如果保持一致,则说明按键状态已经稳定;否则,说明之前检测到的按键信号是抖动信号或外界信号干扰,系统将不会对其进行任何处理。
2 嵌入式Linux设备驱动程序
在Linux内核源代码中,各种驱动程序的代码量占据了整个Linux代码的85%[6]。可见, Linux设备驱动在整个操作系统中起着举足轻重的作用。设备驱动是操作系统内核和机器硬件之间的接口,它们控制着设备的操作动作,并且提供了一组API接口给应用程序,使得应用程序能够与这个设备互动[7]。而且,设备驱动为应用程序屏蔽了硬件的细节,在应用程序看来,硬件设备只是1个设备文件,应用程序就可以像操作普通文件一样对硬件设备进行操作[8]。在Linux操作系统中,通常将外围设备分为3种类型:字符设备、块设备和网络设备[6]。
而在Linux操作系统中,还有一类设备被定义为“平台设备”,通常SoC(System on Chip)系统中集成的独立的外设单元都被当作平台设备来处理,这里把4×5的矩阵键盘也定义为平台设备。所谓的“平台设备”并不是与字符设备、块设备和网络设备并列的概念,而是Linux系统提供的一种附加手段,例如,键盘驱动,它本身是字符设备,但也将其归纳为平台设备。
另外,键盘又属于输入设备,Linux内核提供了输入子系统,如键盘、触摸屏、鼠标等输入设备都可以利用输入子系统的接口函数来实现设备驱动[4]。输入子系统由核心层(Input Core)、驱动层和事件处理层(Event Handler)三部分组成[9]。在Linux内核中,使用输入子系统实现输入设备驱动的时候,驱动的核心工作是向系统报告按键、触摸屏、鼠标等输入事件,而不再需要关心文件操作接口,因为输入子系统已经完成了文件操作接口。通过输入子系统,实现输入设备驱动时只需要完成以下工作:
(1)在模块加载函数中告知输入子系统输入设备可以报告的事件。例如,可通过__set_bit(EV_KEY,input_dev->evbit)来告知输入子系统该设备可报告按键事件。
(2)在模块加载函数中注册输入设备。注册函数为:int input_register_device(struct input_dev *dev);
(3)当有输入事件发生时,如按键按下/抬起、触摸屏被触摸/抬起/移动时,通过input_report_xxx()报告发生的事件及对应的键值、坐标等状态。主要的事件类型包括EV_KEY(按键事件)、EV_REL(相对值,如鼠标移动,报告相对于最后一次位置的偏移)和EV_ABS(绝对值,如触摸屏)。用于报告EV_KEY事件的函数为:void input_report_key(struct input_dev *dev,unsigned int code,int value);
(4)在模块卸载函数中注销输入设备。注销输入设备的函数为:void input_unregister_device(struct input_dev *dev);
3 矩阵键盘驱动中的数据结构
首先,定义一个整型数组osk_keymap[]用来定义按键映射表,把20个按键返回的码值映射成内核中标准的键码,这样有利于与上层应用程序的交互。通过KEY(col,row,code)宏定义来实现映射关系,如要把第2行第4列的按键映射为回车键,则通过KEY(3,1,KEY_ENTER)便可实现。其中KEY_ENTER是内核中定义的标准的键码。
其次,定义矩阵键盘的设备结构体omap_kp,其定义如下:
struct omap_kp {
struct input_dev *input; //定义输入设备结构体指针
struct timer_list timer; //定义计时器
int irq; //中断号
unsigned int rows; //行数
unsigned int cols; //列数
unsigned long delay; //延时
unsigned int debounce; //去抖的间隔时间
int suspended; //判断设备是不是悬停
spinlock_t suspend_lock; //自旋锁
};
4 矩阵键盘驱动程序设计及测试
首先,实现矩阵键盘驱动的加载和卸载函数,分别通过调用platform_driver_register()和platform_driver_unregister()实现矩阵键盘作为一个平台设备的注册和注销。
其次,实现矩阵键盘驱动的探测和移除函数。在探测函数中,初始化行数、列数、中断号以及按键映射表。然后分配内存空间和输入设备,初始化omap_kp这个设备结构体和输入设备结构体input_dev,初始化定时器,设置输入设备可以报告的事件类型,并注册输入设备。最后申请中断,申请中断成功后,使能中断。移除函数则完成相反的工作。
最后,实现矩阵键盘驱动的核心部分,也就是中断部分。众所周知,在Linux的中断处理中分为2部分,分别是顶半部(top half)和底半部(bottom half)[10]。
顶半部完成尽可能少的比较紧急的功能,它只是简单地读取寄存器中的中断状态并清除中断标志后就进行“登记中断”的工作。“登记中断”意味着将底半部处理程序挂到该设备的底半部执行队列中去。这样,顶半部执行的速度就会很快,可以服务更多的中断请求。
底半部,是实现中断处理的真正部分,它来完成一些延缓的耗时任务,首先通过列扫描法检测各个按键状态有没有变化,若有变化再判断是哪一列哪一行发生变化,按键的行和列确定以后,通过键值映射表来查找其有没有对应的键值;若有则通过input_report_key()向内核报告按键的键值;否则,对应的按键没有定义键值,向内核报告为假按键(Spurious Key)。然后,延时(1/20)Hz再判断按键是否抬起。
驱动开发完成后,以模块方式加入到内核,并在MiniGui和Qtopia下进行了测试,在Qtopia下测试结果如图2所示,证明矩阵键盘驱动工作正常、有效。
5 结 语
在此介绍了基于OMAP5912和嵌入式Linux的一种矩阵键盘驱动的工作原理和开发方案。该驱动以静态方式加入内核后,通过测试证明矩阵键盘驱动工作稳定、高效,在MiniGui和Qtopia的记事本中,都能正确显示正确的键值,基本上实现了其功能,并成功地应用于所开发的嵌入式语音识别系统中。
参考文献
[1]OMAP5912 Applications Processor Data Manual[S].2004.
[2]韩金燕,卢素锋,王胜坤.一种基于TI OMAP的PDA的设计[J].电脑开发与应用,2007,20(2):47-49.
[3]OMAP5912 Multimedia Processor Keyboard InterfaceReference Guide[S].2004.
[4]宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2008.
[5]李杰,曹宇,朱坚,等.基于嵌入式Linux的矩阵键盘设计与实现[J].现代电子技术,2006,24(3):81-83.[6]孙天泽.嵌入式设计及Linux驱动开发指南基于ARM9处理器[M].北京:电子工业出版社,2007.
[7]祝世海.嵌入式微处理器的Linux设备驱动程序开发[J].哈尔滨商业大学学报:自然科学版,2007,23(3):329-331.
[8]李世勇,肖竟华.基于Linux驱动程序的编写技术[J].电脑与信息技术,2006,14(3):43-45.
[9]Alessandro Rubini,Jonathan Corbet,Gerg Kroah-Hartman.Linux Device Drivers.Third Edition.O′Reilly,2008.
[10]王兵,王冰峰.嵌入式Linux按键驱动程序的设计[J].科技资讯,2007(1):220-223.
作者简介 杨斌斌 男,1983年出生,山西新绛人,在读硕士研究生。研究方向为语音信号处理与嵌入式系统。
张雪英 女,太原理工大学教授、博士生导师。研究方向为语音信号处理。