Linux驱动开发之五---按键驱动(查询方式)(Tiny6410)

来源:互联网 发布:制作电子相册软件 知乎 编辑:程序博客网 时间:2024/04/27 20:38

在Linux驱动程序开发之三----按键驱动(Tiny6410)博文中讨论了使用中断来实现按键驱动,毫无疑问,中断方式效率相当高,但是在此之前,CPU要想获知按键的状态都是通过查询方式来实现的,查询方式就是CPU不停的检查按键的状态,如果有变化则立即输出,而中断是外设向CPU传递消息,告诉CPU自己状态改变了,要求CPU进行处理,而其他时间CPU可以做自己想做的事情,和微机原理以及操作系统课程中讲的一样,代码实现如下:

首先编写驱动框架,然后配置KEY值的GPIO管脚为输入,然后实现read函数,在read函数中读取KEY值,并拷贝到用户空间,用户程序则不停的读取按键的状态,如果变低则输出一条消息,否则不输出。Tiny6410中按键的电路图如下:


当未按下时,K1~K8为高电平,当按下后为低电平。

按键对应GPIOKEYGPIO管脚KEY1GPN0KEY2GPN1KEY3GPN2KEY4GPN3KEY5GPN4KEY6GPN5KEY7GPL11KEY8GPL12详细代码如下:

#include <linux/module.h>//MODULE_LICENSE,MODULE_AUTHOR#include <linux/init.h>//module_init/module_exit#include <linux/fs.h>//file_operations#include <asm/io.h>//ioread32,iowrite32#include <linux/cdev.h>//cdev#include <mach/map.h>//定义了S3C64XX_VA_GPIO#include <mach/regs-gpio.h>//定义了gpio-bank-n中使用的S3C64XX_GPN_BASE#include <mach/gpio-bank-n.h>//定义了GPNCON#include <mach/gpio-bank-l.h>//定义了GPNCON#include <linux/wait.h>//wait_event_interruptible(wait_queue_head_t q,int condition);//wake_up_interruptible(struct wait_queue **q)#include <linux/sched.h>//request_irq,free_irq#include <asm/uaccess.h>//copy_to_user#include <linux/irq.h>//IRQ_TYPE_EDGE_FALLING#include <linux/interrupt.h>//request_irq,free_irq#include <linux/device.h>//class deviceMODULE_AUTHOR("jefby");MODULE_LICENSE("Dual BSD/GPL");MODULE_DESCRIPTION("Tiny 6410 buttons with search");#define GPNCON 0x7F008830#define GPLCON0 0x7F008810static volatile unsigned int * gpncon = NULL;static volatile unsigned int * gpndat = NULL;static volatile unsigned int * gplcon = NULL;static volatile unsigned int * gpldat = NULL;//按键设备的主设备号static int buttons_major = 0;//设备号dev_t dev;//字符设备struct cdev * buttons_cdev;static struct class * tiny6410_buttons_class = NULL;static struct device * tiny6410_buttons_device = NULL;//设备打开操作,主要完成BUTTONS所对应的GPIO的初始化,注册用户中断处理函数int  buttons_open(struct inode *inode,struct file *filp){unsigned val;/*设置buttons对应的GPIO管脚,设置KEY1~KEY6*/gpncon = (volatile unsigned int*)ioremap(GPNCON,16);gpndat = gpncon + 1;val = ioread32(gpncon);//读取GPNCON的值val = (val & ~(0xFFF));//设置GPIO 0~5为输入iowrite32(val,gpncon);//设置KEY7,KEY8为输入,gpl11,gpl12gplcon = (volatile unsigned int*)ioremap(GPLCON0,16);gpldat = gplcon + 2;//gpldatval = ioread32(gplcon+1);//读取GPNCON1的值val = (val & ~(0xFF<<12));//设置GPL11和12为输入iowrite32(val,gplcon+1);/*val = ioread32(S3C64XX_GPLCON1);val = (val & ~(0xFF<<12)) | (0x33);iowrite32(val,S3C64XX_GPLCON1);*/printk("buttons open.\n");return 0;}//按键读若没有键被按下,则使进程休眠;若有按键被按下,则拷贝数据到用户空间,然后清零int buttons_read(struct file *filp, char __user *buf, size_t len, loff_t * pos){unsigned char keyval[8]={0};unsigned int temp=0;int i=0;if(len != 8)return -1;temp=ioread32(gpndat);//读取KEY1~KEY6的值for(i=0;i<6;++i){keyval[i] = (temp&(0x1<<i))?1 : 0;}temp = ioread32(gpldat);//读取KEY7和KEY8的值keyval[6]=(temp&(0x1<<11))?1:0;keyval[7]=(temp&(0x1<<12))?1:0;copy_to_user(buf,keyval,sizeof(keyval));return 0;}//主要是卸载用户中断处理程序int buttons_close(struct inode *inode,struct file *filp){printk("buttons close.\n");return 0;}static struct file_operations buttons_fops = {.owner = THIS_MODULE,.read = buttons_read,.release = buttons_close,.open = buttons_open,};/*模块初始化:1.申请设备号,默认使用动态分配的方法2.申请并初始化cdev结构3.将cdev注册到内核*/static int module_buttons_init(void){int err=0;int result=0;printk("Tiny6410 buttons module init.\n");if(buttons_major){dev = MKDEV(buttons_major,0);result = register_chrdev_region(dev,1,"buttons");}else{result = alloc_chrdev_region(&dev,0,1,"buttons");buttons_major = MAJOR(dev);}if(result < 0){printk(KERN_WARNING "buttons : can't get major %d\n",buttons_major);}printk("buttons major is %d",buttons_major);buttons_cdev = cdev_alloc();buttons_cdev ->ops = &buttons_fops;cdev_init(buttons_cdev,&buttons_fops);cdev_add(buttons_cdev,dev,1);tiny6410_buttons_class = class_create(THIS_MODULE, "tiny6410buttons");if (IS_ERR(tiny6410_buttons_class)) {err = PTR_ERR(tiny6410_buttons_class);printk("create class error.\n");}tiny6410_buttons_device = device_create(tiny6410_buttons_class, NULL, MKDEV(buttons_major, 0), NULL,      "buttons");printk("buttons add ok.\n");return 0;}static void module_buttons_exit(void){iounmap(gpncon);device_destroy(tiny6410_buttons_class, MKDEV(buttons_major, 0));class_destroy(tiny6410_buttons_class);cdev_del(buttons_cdev);unregister_chrdev_region(dev,1);printk("Tiny6410 buttons module exit");}module_init(module_buttons_init);module_exit(module_buttons_exit);

用户程序的代码如下:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>int main(int argc,char **argv){int i;int ret;int fd;unsigned char keyval[8]={1,1,1,1,1,1,1,1};static int cnt = 0;//打开设备fd = open("/dev/buttons",0);if(fd < 0){printf("can't open /dev/buttons\n");return -1;}while(1){for(i=0;i<8;++i){ret = read(fd,keyval,sizeof(keyval));if(ret < 0){printf("read err.\n");return -1;}if(keyval[i] == 0){printf("%d:KEY%d entered.\n",cnt++,i+1);}}//for}//while(1)close(fd);return 0;}

运行截图如下:


可以看出每按下一次就会打印出一串消息,说明那个按键被按下。使用top命令查看当前的CPU使用率,截图如下:可以看出,查询方式下确实效率太低了,CPU被占用了90%多以上


0 0
原创粉丝点击