230 likes | 374 Vues
嵌入式键盘驱动. 广州嵌入式软件公共技术支持中心 梁老师 2007 年 04 月. 矩阵式键盘原理. 矩阵式键盘一般适用于按键数量较多的场合,它由行线和列线组成,按键位于行、列的交叉点上。 如图所示,一个 4×4 的行、列结构可以构成一个有 16 个按键的键盘。. 矩阵式键盘原理. 按键设置在行、列交叉点上,行、列分别连接到按键开关的两端。行线通过上拉电阻接到十 5 V 上。
E N D
嵌入式键盘驱动 广州嵌入式软件公共技术支持中心 梁老师 2007年04月
矩阵式键盘原理 • 矩阵式键盘一般适用于按键数量较多的场合,它由行线和列线组成,按键位于行、列的交叉点上。 • 如图所示,一个4×4的行、列结构可以构成一个有16个按键的键盘。
矩阵式键盘原理 • 按键设置在行、列交叉点上,行、列分别连接到按键开关的两端。行线通过上拉电阻接到十5 V上。 • 平时无按键动作时,行线处于高电平状态;而当有健按下时,行线电平状态将由通过此按键的列线电平决定:列线电平如果为低,行线电平为低;列线电平如果为高,则行线电平亦为高。这一点是识别矩阵式键盘是否被按下的关键所在。
矩阵式键盘原理 • 矩阵键盘按键的识别方法分两步进行: • ①识别键盘哪一行的键被按下。让所有列线均为低电平,检查各行线电平是否为低。如果有行线为低,则说明该行有键被按下,否则说明无键被按下。 • ②如果某行有键被按下,识别键盘哪一列的键被按下(亦称之为扫描法)。逐列置低电平,并置其余各列为高电平.检查各行线电平的变化。如果行电平变为低电平,则可确定此行此列交叉点处按键被按下。
S3C2410 的I/O 介绍 • S3C2410 有117 个复用功能输入输出端口引脚,这些引脚是: • PortA(GPA):32 个输入/输出端口 • PortB(GPB):11 个输入/输出端口 • PortC(GPC):16 个输入/输出端口 • PortD(GPD):16 个输入/输出端口 • PortE(GPE):16 个输入/输出端口 • PortF(GPF):8 个输入/输出端口 • PortG(GPG):16 个输入/输出端口 • PortH(GPH):11 个输入/输出端口
S3C2410 的I/O 介绍 • 端口控制说明 • 端口配置寄存器(GPACON――GPHCON) 大部分的引脚是复用的,所以必须对于每个引脚要求定义一个功能,端口配置寄存器定义了每个引脚的功能。 • 端口数据寄存器(GPADAT――GPHDAT) 如果端口配置成输出端口,数据能够被写到端口数据寄存器的对应位,然后通过管脚输出。如果端口配置成输入端口,能从端口数据寄存器对应的位中读出管脚上的电平 • 端口上拉寄存器(GPBUP――GPHUP) 端口上拉寄存器控制着每个端口组的上拉寄存器的使能或禁止,当对应位为0,这个引脚的上拉寄存器是允许的,当为1 时,上拉寄存器是禁止的。
MIZI提供的S3C2410.H • 使用一个32位的数来表示端口的使用情况。 • 模式 |上拉 |端口 | 端口引脚 • MODE | PULLUP | PORT | OFS • 不需要自己手动组合,通过宏定义以及SHIFT和MASK组合。见程序
MIZI提供的S3C2410.H • 端口的表示 • #define PORTA_OFS 0 • #define PORTB_OFS 1 • #define PORTC_OFS 2 • #define PORTD_OFS 3 • #define PORTE_OFS 4 • #define PORTF_OFS 5 • #define PORTG_OFS 6 • #define PORTH_OFS 7
MIZI提供的S3C2410.H • 端口引脚的表示 • #define GPIO_A0 MAKE_GPIO_NUM(PORTA_OFS, 0) • #define GPIO_A1 MAKE_GPIO_NUM(PORTA_OFS, 1) • #define GPIO_A2 MAKE_GPIO_NUM(PORTA_OFS, 2) • #define GPIO_A3 MAKE_GPIO_NUM(PORTA_OFS, 3) • 。。。 • #define MAKE_GPIO_NUM(p, o) ((p << GPIO_PORT_SHIFTT) | (o << GPIO_OFS_SHIFT))
MIZI提供的S3C2410.H • set_gpio_ctrl(x) • 功能:配置端口引脚的功能,设置IO口控制寄存器和上拉寄存器 • 用法:set_gpio_ctrl(模式|上拉?|IO脚) • 模式|是否上拉|IO脚,在S3C2410.h中都有其定义好的名字。 • set_gpio_ctrl(GPIO_E11 | GPIO_PULLUP_DIS |GPIO_MODE_OUT);
MIZI提供的S3C2410.H • write_gpio_bit(x, v) • 功能:把端口 对应的端口数据寄存器x位设置为v • write_gpio_bit(GPIO_E11, 0); • read_gpio_bit(x) • 功能:把端口数据寄存器x位的状态 读入,函数返回值既是其状态 • read_gpio_bit(GPIO_G11);
MIZI提供的S3C2410.H • write_gpio_reg(x, v) • 功能:把端口数据寄存器x 设置为v • read_gpio_reg(x) • 功能:读取端口数据寄存器x,函数返回值既是其数据
键盘的硬件实现 • 4X4 矩阵键盘 • 四个输入引脚: • EINT0 -----( GPF0 )----INPUT • EINT2 -----( GPF2 )----INPUT • EINT11-----( GPG3 )----INPUT • EINT19-----( GPG11 )----INPUT • 四个输出引脚: • KEYSCAN0---( GPE11 )----OUTPUT • KEYSCAN1---( GPG6 )----OUTPUT • KEYSCAN2---( GPE13 )----OUTPUT • KEYSCAN3---( GPG2 )----OUTPUT
键盘的驱动实现 • 引入结构体key_info对按键进行描述 • static struct key_info { • int irq_no; //外部中断号 • unsigned int gpio_port; //输入端口,EINT • unsigned int gpio_port_kscan; //输出端口,OUTPUT • int key_no; //按键序号,或者名字 • } key_info_tab[16] = { • …… • }
键盘初始化程序 • static int __init matrix4_buttons_init(void) • { • 注册字符设备 register_chrdev(……); • 初始化按键对应的输出端口 buttons_io_port_init(); • 采用中断机制,注册中断号 request_irqs(); • }
键盘初始化程序 • /* 初始化kscan口为输出0 */ • static void buttons_io_port_init(void) • { • int i; • for(i=0; i < sizeof kscan / sizeof kscan[1]; i++) { • set_gpio_ctrl(kscan[i] | GPIO_PULLUP_DIS | GPIO_MODE_OUT); • write_gpio_bit(kscan[i], 0); • } • }
请求注册中断 • static int request_irqs(void) • { • for (i = 0; i < 使用中断个数; i++) { • 设置与外部中断号相对应的GPIO端口以及模式请求中断号,并注册中断响应函数。 • } • }
键盘驱动的卸载函数 • static void __exit matrix4_buttons_exit(void) • { • 释放中断 free_irqs(…); • 注销字符设备unregister_chrdev(…); • }
按键中断处理 buttons_irq • static void buttons_irq(int irq, void *dev_id, struct pt_regs *reg) • { • 设置GPIO为输入状态 • 键盘扫描 • 唤醒按键等待队列的进程 • 重新设置GPIO为输出 • 重新设置中断 • }
通过延时去键盘抖动 • 理想的情况下,当按键被按下时,I/O口电平被拉低,即逻辑0,当按键松开时,为逻辑1。 • 但实际机械的触点动作与微处理器快速的执行速度不匹配,导致开关被按下或松开时产生抖动,如同弹簧一样,不能立刻产生稳定的0或1。 • 常用的去抖动方法有硬件和软件两种,硬件可采用单稳态触发起、高通滤波器等硬件实现,但该方法一般要对每一路输入添加特殊的硬件,比较复杂。软件去抖动则简单多了,可通过增加延时和判断来解决。
matrix4_buttons_fops • 由于按键不具有I/O功能,它只会在按下的时候产生中断,所以这里不需要实现open,read,write,ioctl等功能。 • 为了测试驱动,可以添加这些函数。