基于嵌入式Linux内核的键盘驱动控制模块设计

发布者:静静思索最新更新时间:2018-02-05 来源: eefocus关键字:Linux内核  键盘驱动  控制模块 手机看文章 扫描二维码
随时随地手机看文章

    为了适应嵌入式设备外设的多样性,本文以特殊矩阵键盘为例,设计了一套完整的驱动控制模块。硬件电路设计采用外扩3片SN74HC 164芯片的方式,节省了GPIO引脚的使用,大大提高了利用效率。同时,在此基础上引出了Linux内核中input子系统的特性和工作机制,呈现了较为完整的输入事件由内核空间传递到用户空间进程的过程。实验结果表明,设计的驱动模块具有良好的实时性和准确性。

    随着微处理器技术的不断发展和数字化产品的普及,嵌入式系统的研究开发逐渐成为热点,Linux也以其开源、稳定、可裁剪的优势成为嵌入式操作系统的主流。在众多的嵌入式系统中,键盘成为一种应用最为广泛的输入设备。然而,嵌入式设备的功能差异性又决定了为其提供一种通用性键盘是不可行的,往往需要根据系统的实际功能设计所需的特殊键盘,并实现相应的驱动程序。
    S3C6410是三星公司高性能的32位RISC微处理器,内部集成了多种强大的硬件加速器,适合进行视频和图像处理,成为了目前嵌入式处理器领域的主流产品。本文以在S3C6410微处理器基础上实现一个24键矩阵键盘为例,呈现了在嵌入式系统中开发设备驱动程序的整体流程,并对Linux系统下输入事件的底层传递机制进行了研究和分析。

1 接口电路的设计
    在嵌入式设备上扩展键盘的常用方式是通过对CPU的GPIO端口进行扫描实现的,显然这种方式在键盘按键数目较多的情况下,会占用过多的GPIO资源,增加了GPIO端口资源较为紧张的嵌入式处理器的负担。
    本系统的硬件设计通过增加3片SN74HC164芯片来达到节约GPIO资源的目的。SN74HC164是一种8位的串行输入、并行输出移位寄存器,它的内部由8个D触发器串联而成。每当时钟信号由低电平变为高电平时,两个输入端将当前输入信号传送到并行输出端,并实现移位操作。系统硬件原理图如图1所示。

a.JPG

    
    3个SN74HC164芯片串联后,将它们的CLK引脚接到S3C6410开发板的GPE4端口上。第一个SN74HC164芯片的A、B输入引脚共同接到开发板的GPE3端口上,并且将这两个GPIO端口配置成输出模式。GPE2端口与键盘按键的上拉端连接,系统运行时在中断模式和输入模式之间切换,以达到触发中断和对键盘扫描的目的。这样我们就借助于3个SN74HC164移位寄存器,只占用3个GPIO端口,给扫描键盘的24个按键提供输入信号,既节约了成本,又避免了GPIO资源的浪费。

2 扫描工作原理
    扩展硬件电路的同时给键盘驱动程序的实现带来了一定的麻烦,驱动程序首先要将SN74HC164驱动起来,然后才能对电路进行控制。该电路的输出引脚被接到S3C6410的GPE2端口上,并且这个端口被配置成中断源,无键按下时直接读为高电位。键盘扫描时通过SN74HC164芯片先将键盘的24个键置低电平,任何一个键被按下,GPE2端口就会有从高电平到低电平的跳变,从而触发一次中断。
    在中断处理过程中,将GPE2端口置为输入状态。然后根据SN74HC164芯片的输入/输出特性,给串联的3个SN74HC164芯片发送24个高电平信号,使得键盘的各键位均为高电平。在随后的24个时钟脉冲下,给SN74HC164芯片送入1个0和23个1,使得0在每个键位的输入端都只出现一次,同时在GPE2端口进行扫描。当被按下键处于0输入状态时,其所在行就会读到一个低电平,也就可以确定出键盘上哪个键被按下了。

3 驱动模块结构
    在Linux2.6的版本中新加入了input子系统,给驱动编写者提供了一个完整的输入事件——从底层设备传递到用户进程的模型。本文基于input子系统架构,设计了一个较为完善的特殊键盘驱动模块。键盘驱动模块结构如图2所示。

b.JPG

    
    在input子系统的设备内核模型中,最重要的数据结构体是struct input_dev,作为驱动的主体,每个structinput_dev代表一个输入设备。该结构体中既包含了设备所能响应的输入事件类型、响应按键种类、键盘码表,以及坐标范嗣等字段,同时还包含了设备打开、关闭以及回调函数等字段,能够完整地记录和标识整个设备的功能与行为。在向内核注册input_dev之前,需要进行input_dev结构的初始化,同时向内核申请键盘中断。

    首先设置输入设备的功能,input_set_capability(&sim_key,EV_KEY,KEY_A)函数完成键盘A键的输入使能,类似可完成B~X共24个按键的输入使能。然后设置键盘的码表。该键盘包含20个按键,码表可表示为:statIC unsigned char sim_keycode[24]={KEY_A,KEY_B,KEY_C,KEY_D,KEY_E,KEY_F,KEY_G,KEY_H,KEY_I,KEY_J,KEY_K,KEY_L,KEY_M,KEY_N,KEY_O,KEY_P,KEY_Q,KEY_R,KEY_S,KEY_T,KEY_U,KEY_V,KEY_W,KEY_X)。当相应键按下时,码表中的键值将被作为键盘码上报到用户空间的进程。初始化工作完成之后,调用函数input_register_device(&sim_kb)向内核注册输入设备。
    由于键盘设备的输入是异步的,可能会在任何时间得到按键事件,所以需向内核申请中断以保证对键盘输入的实时响应。中断函数完成键盘的扫描操作,并上报输入事件到用户进程,是整个驱动模块的功能主体。然而使用中断会遇到一个问题,在键盘的扫描过程中,按键的每次按下和抬起都会有10~20 ms的毛刺抖动存在,会将用户的一次按键操作误当作几次按键来处理。所以为了获取稳定的按键信息,必须要想办法去掉这种抖动。去毛刺的一种常见的方法是在注册输入设备时定义一个定时器timer,当触发中断时先关闭I/O中断,然后启动定时器,等跳过毛刺抖动以后再去调用扫描程序得到键值,并重新打开中断。按键事件被发送到input子系统核心后通知给用户进程,从而实现查键过程。

4 基于input子系统的事件传递机制
    实现底层驱动程序与用户进程通信的最主要的函数是input_event(struct input_dev * dev,unsigned int type,unsigned int code,int value),也是input输入子系统的核心,其实现机制如下。
    Linux系统在启动过程中会向系统核心注册input_handler,一般将其称为handler处理器,表示对输入事件的具体处理,input_handler为输入设备的功能实现了一个接口。在执行input_register_device注册输入设备的时候,会自动将input_dev结构与系统中已注册的input_
handler进行遍历匹配。与对应的input_handler成功匹配后,Linux内核自动创建evdev结构体来表示输入事件设备,该结构中包含了input _handle等字段,作为连接input_dev与input_handler的媒介。其中Linux内核中与键盘设备匹配的input_handler代码为:
    static struct input_handler evdev_handler={
          .event=evdev_event,
          .connect=evdev_connect,
          .disconnect=evdev_disconnect,
          .fops=&evdev_fops,
          .minor=EVDEV_MINOR_BASE,
          .name=“evdev”,
          .id_table=evdev_ids,
    };
    evdev_event函数为事件处理函数,输入设备所上报的事件通过evdev_handler中的evdev_event函数包装成input_event标准输入格式,并存放在evdev下的evdev_list缓冲区中,该结构代码如下:
    struct input_event{
          struct timeval time; //事件发生的时间
          __u16 type; //事件类型
          __u16 code; //子事件
          __s32 value; //事件发生的相关值
    };
    用户进程读取键盘事件时即会按照此种特定格式进行。值得注意的是,当读取事件为鼠标输入时,需要先后读取X轴坐标和Y轴坐标两种数据,以完成完整的读取操作。
    在Linux系统中,所有的外设都是通过虚拟文件系统向应用程序提供接口,所以每个具有独立功能的外设在Linux系统中都对应着相应的设备文件。同时,在内核中代表设备文件的结构体包含了实现该设备功能的特定操作函数。
    完成驱动模块的安装之后,Linux系统会在/devr目录下自动创建输入事件设备文件,本文中该设备名为event0。用户进程打开对应的输入事件设备文件event0,即可执行相应的文件操作,如rcad、ioctl等。文件操作函数最终要进入内核,并调用存储在事件设备结构体中的
evdev_handler.evdev_fops操作函数集完成对应的文件操作。
    e.JPG
    例如用户进程在执行rcad操作时,会调用内核中evdev_fops->evdev_rcad函数,先判断当前输入事件设备缓冲区中是否有待读取的input _event事件。若缓冲区中无按键事件,进程则放入等待队列进行睡眠,直到有按键事件产生并保存到缓冲区后,将睡眠进程唤醒,调用copy_ to_user复制函数完成输入事件从内核空间到用户空间的拷贝,从而实现读取操作。

结语
    通过以上分析可以得出,键盘设备所产生的输入事件以input子系统为传递介质,并通过虚拟文件系统接口得以通知用户进程。本文从键盘的驱动开发出发,呈现了较为完整的输入事件由内核空间传递到用户空间进程的过程,对于驱动开发者了解底层驱动的机制和更加有效地设计驱动模块有着较为重要的意义。经过测试,该键盘具有良好的响应特性,并实现了所预期的功能。

关键字:Linux内核  键盘驱动  控制模块 引用地址:基于嵌入式Linux内核的键盘驱动控制模块设计

上一篇:基于ARM9核的AT91RM9200微处理器的短消息监控系统的设计与实现
下一篇:基于RS485接口的MODBUS串口编程的实现

推荐阅读最新更新时间:2024-03-16 15:54

TQ210 —— s5pv210 Linux内核结构
1、内核的子系统 (1) 系统调用接口SCI(System Call Interface):SCI层为用户空间提供了一套标准的系统调用函数来访问Linux内核,搭起了用户空间到内核空间的桥梁。 (2) 进程管理PM(Process Management):进程作为资源分配的基本单位而存在;进程调度。 (3) 虚拟文件系统VFS(Virtual File System):它是一种用于网络环境的分布式文件系统,是允许和操作系统使用不同的文件系统实现的接口。 (4) 内存管理MM(Memory Management):段转换过程是由逻辑地址(或称为虚拟地址)转换为线性地址;页转换过程则是将线性地址转换为物理地址。 (5) 网络协议栈(N
[单片机]
基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九-2)
平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本:Linux-4.4.0 (支持device tree) u-boot版本:友善之臂自带的 U-Boot 2010.12 (为支持uImage启动,做了少许改动) busybox版本:busybox 1.25 交叉编译工具链: arm-none-linux-gnueabi-gcc (gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-29)) 摘要 上一篇 博文在tiny4412上移植了MMA7660驱动程序,使用的是exynos4
[单片机]
基于tiny4412的<font color='red'>Linux内核</font>移植 -- MMA7660驱动移植(九-2)
linux内核移植s3c2410,准备工作,继续
vmlinux在链接时,使用的文件是在vmlinux-all中定义的所有文件,链接俄脚本是在arch/arm/kernel/vmlinux.lds中定义该如何 链接这些文件。 总结上面: 真个的 linux的源码是通过Makefile来实现项目的 管理的,顶层的Makefile定义了那些文件夹 中的 内容 被编译进内核,各级 的子目录下的Makefile决定该目录下的那些文件被编译进内核。 对于编译选项的设置的话,存在全局的,局部的和仅对一个文件 起作用的选项。 3.内核的Kconfig文件的 分析 在linux内核目录下,如果直接使用make menuconfig的话,出现的配置界面就是使用的是Kbuild来实现的。最终通过ma
[单片机]
2410的linux内核启动地址30008000 由来探讨
以下就2.4内核中的文件对此问题进行分析。 内核编译链接过程是依靠vmlinux.lds文件,以arm为例vmlinux.lds文件位于kernel/arch/arm/vmlinux.lds, vmlinux-armv.lds的生成过程在kernel/arch/arm/Makefile中 ifeq ($(CONFIG_CPU_32),y) PROCESSOR = armv TEXTADDR = 0xC0008000 LDSCRIPT = arch/arm/vmlinux-armv.lds.in endif arch/arm/vmlinux.lds: $(LDSCRIPT) dummy @sed 's/TEXTADDR/$
[嵌入式]
负载控制模块制作与应用原理
负载控制模块(LOAD CONTROL ELEMENT)简称LCE是一种能够判别电路中是否接有负载,并利用有无负载的信息来控制其它负载工作的电路。它具有联运效应,其用途甚广。本文介绍一种利用两只双向可控硅元件自由市场制作的LCE模块具有结构简单、成本低廉、负载功率大、灵敏度高和制作容易等特点,是一种尚待开发利用的新型电力电子负载控制器。   该装置的内部电路工作原理如图A所示。由于其线路异常简单,两个双向可控硅有机地连接在一起,就产生了奇妙的功能,这也许能够给电子爱好者一个很好的启示。该LCE的最大特点是不用另加直流电源,呈全固态电路形式,具有无工作噪声和良好的防爆性能。它总共只有3只引脚:①脚是从动负载串联端;②脚是主
[工业控制]
负载<font color='red'>控制模块</font>制作与应用原理
汽车制造中Pilz安全控制模块的应用
对于汽车制造工业的不同车间和设备,安全产品的正确选择、设计和使用,对于成本的降低、设备的安全可靠性、维护的便易性至关重要。 在整个安全控制电气系统中,安全控制模块最为复杂。因为安全控制模块,既要采集安全输入信号,并且根据逻辑要求,进行安全的输出控制。安全控制模块不但在自身出现缺陷的情况下依然要能够保持高安全可靠性,同时也要能够检测安全输入信号和被控输出元件的故障,并及时做出合理的反应。在安全控制领域,常用的安全控制模块有安全继电器、安全可编程控制器、安全总线系统。 Pilz紧凑型安全继电器PNOZX、elog和Sigma系列可以用于控制单一安全功能,适用于小型的安全控制系统。其安全输出通常有继电器触点输出或晶体管输出。无论
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved