微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 嵌入式Linux设备驱动开发之:按键驱动程序实例

嵌入式Linux设备驱动开发之:按键驱动程序实例

时间:09-13 来源:互联网 点击:

11.6按键驱动程序实例

11.6.1按键工作原理

LED和蜂鸣器是最简单的GPIO的应用,都不需要任何外部输入或控制。按键同样使用GPIO接口,但按键本身需要外部的输入,即在驱动程序中要处理外部中断。按键硬件驱动原理图如图11-7所示。在图11-7的4×4矩阵按键(K1~K16)电路中,使用4个输入/输出端口(EINT0、EINT2、EINT11和EINT19)和4个输出端口(KSCAN0~KSCAN3)。

图11.7按键驱动电路原理图

按键驱动电路使用的端口和对应的寄存器如表11-18所示。

表11.18 按键电路的主要端口

管脚

端口

输入/输出

管脚

端口

输入/输出

KEYSCAN0

GPE11

输出

EINT0

EINIT0/GPF0

输入/输出

KEYSCAN1

GPG6

输出

EINT2

EINT2/GPF2

输入/输出

KEYSCAN2

GPE13

输出

EINT11

EINT11/GPG3

输入/输出

KEYSCAN3

GPG2

输出

EINT19

EINT19/GPG11

输入/输出

因为通常中断端口是比较珍贵且有限的资源,所以在本电路设计中,16个按键复用了4个中断线。那怎么样才能及时而准确地对矩阵按键进行扫描呢?

某个中断的产生表示,与它所对应的矩阵行的4个按键中,至少有一个按键被按住了。因此可以通过查看产生了哪个中断,来确定在矩阵的哪一行中发生了按键操作(按住或释放)。例如,如果产生了外部2号线中断(EINT2变为低电平),则表示K7、K8、K9和K15中至少有一个按键被按住了。这时候4个EINT端口应该通过GPIO配置寄存器被设置为外部中断端口,而且4个KSCAN端口的输出必须为低电平。

在确定按键操作所在行的位置之后,我们还得查看按键操作所在列的位置。此时要使用KSCAN端口组,同时将4个EINT端口配置为通用输入端口(而不是中断端口)。在4个KSCAN端口中,轮流将其中某一个端口的输出置为低电平,其他3个端口的输出置为高电平。这样逐列进行扫描,直到按键所在列的KSCAN端口输出为低电平,此时按键操作所在行的EINT管脚的输入端口的值会变成低电平。例如,在确认产生了外部2号中断之后,进行逐列扫描。若发现在KSCAN1为低电平时(其他端口输出均为高电平),GPF2(EINT2管脚的输入端口)变为低电平,则可以断定按键K8被按住了。

以上的讨论都是在按键的理想状态下进行的,但实际的按键动作会在短时间(几毫秒至几十毫秒)内产生信号抖动。例如,当按键被按下时,其动作就像弹簧的若干次往复运动,将产生几个脉冲信号。一次按键操作将会产生若干次按键中断,从而会产生抖动现象。因此驱动程序中必须要解决去除抖动所产生的毛刺信号的问题。

11.6.2按键驱动程序

首先按键设备相关的数据结构的定义如下所示:

/*butt_drv.h*/

……

typedefstruct_st_key_info_matrix/*按键数据结构*/

{

unsignedcharkey_id;/*按键ID*/

unsignedintirq_no;/*对应的中断号*/

unsignedintirq_gpio_port;/*对应的中断线的输入端口地址*/

unsignedintkscan_gpio_port;/*对应的KSCAN端口地址*/

}st_key_info_matrix;

typedefstruct_st_key_buffer/*按键缓冲数据结构*/

{

unsignedlongjiffy[MAX_KEY_COUNT];/*按键时间,5s以前的铵键作废*/

unsignedcharbuf[MAX_KEY_COUNT];/*按键缓冲区*/

unsignedinthead,tail;/*按键缓冲区头和尾*/

}st_key_buffer;

……

下面是矩阵按键数组的定义,数组元素的信息(一个按键信息)按照0行0列,0行1列,…,3行2列,3行3列的顺序逐行排列。

staticst_key_info_matrixkey_info_matrix[MAX_COLUMN][MAX_ROW]=

{

{{10,IRQ_EINT0,S3C2410_GPF0,S3C2410_GPE11},/*0行0列*/

{11,IRQ_EINT0,S3C2410_GPF0,S3C2410_GPG6},

{12,IRQ_EINT0,S3C2410_GPF0,S3C2410_GPE13},

{16,IRQ_EINT0,S3C2410_GPF0,S3C2410_GPG2}},

{{7,IRQ_EINT2,S3C2410_GPF2,S3C2410_GPE11},/*1行0列*/

{8,IRQ_EINT2,S3C2410_GPF2,S3C2410_GPG6},

{9,IRQ_EINT2,S3C2410_GPF2,S3C2410_GPE13},

{15,IRQ_EINT2,S3C2410_GPF2,S3C2410_GPG2}},

{{4,IRQ_EINT11,S3C2410_GPG3,S3C2410_GPE11},/*2行0列*/

{5,IRQ_EINT11,S3C2410_GPG3,S3C2410_GPG6},

{6,IRQ_EINT11,S3C2410_GPG3,S3C2410_GPE13},

{14,IRQ_EINT11,S3C2410_GPG3,S3C2410_GPG2}},

{{1,IRQ_EINT19,S3C2410_GPG11,S3C2410_GPE11},/*3行0列*/

{2,IRQ_EINT19,S3C2410_GPG11,S3C2410_GPG6},

{3,IRQ_EINT19,S3C2410_GPG11,S3C2410_GPE13},

{13,IRQ_EINT19,S3C2410_GPG11,S3C2410_GPG2}},

};

下面是与按键相关的端口的初始化函数。这些函数已经在简单的GPIO字符设备驱动程序里被使用过。此外,set_irq_type()函数用于设定中断线的类型,在本实例中通过该函数将4个中断线的类型配置为下降沿触发式。

staticvoidinit_gpio(void)

{

s3

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top