关于《详解》第12.1节按键驱动的进一步阐述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34367257/article/details/85053762
《详解》12.1的按键驱动,是本书的最大失误,应大家的要求,我们很有必要对其进行再次阐述。
         注意标题是“按键”驱动而非“键盘”驱动,按键往往是一个按钮直接对应于一个可中断的GPIO,而键盘则有一个行列矩阵,有一个扫描的过程,由键盘控制器负责扫描、去抖动、得到键值等工作。
         按键驱动的目的是在用户调用read()的时候能够读出来正确的键值,如果用户以阻塞方式打开,则在没有按键事件的情况下,驱动应切出本进程,之后等待按键事件唤醒之。
        因为在一个键被按下的时候,有一定时间的抖动,也就是说刚按下去的时候会弹来弹去数次,这些事件应该被忽略。有的SoC的中断控制器本身支持 debounce功能,会在硬件上去抖,就不再需要软件去抖,否则,软件上最好去抖动。去抖的常规思路是:当一个键被按下的时候,启动一个定时器延迟数十 ms,如果在定时器到期后,键还是按下的,就正式确认一个按下事件,这样,中间数十ms的弹来弹去就自动被过滤掉了。这就是在代码清单12.8的ISR中 启动一个定时器的原因,注意在第6行,只是将状态置为了KEYSTATUS_DOWNX而不是KEYSTATUS_DOWN,在状态是 KEYSTATUS_DOWNX的情况下,从代码清单12.9(timer handler)的第6至13行可以看出,如果还是按下的,就确认确实按下了,将状态置为KEYSTATUS_DOWN。
        为了实现阻塞方式地访问,在没有按键事件的情况下,如果用户调用read(),本进程应该睡眠直到发生按键事件。在代码清单12.11中 s3c2410_key_read()的第17行会通过interruptible_sleep_on()睡眠等待按键事件,而代码清单12.9调用的 keyEvent()中做的事情就是讲一个按键事件放入keydev.head和keydev.tail所管理的事件队列(放入后将使得 keydev.tail != keydev.head成立),这样,在第17行的interruptible_sleep_on()醒来后,跳转执行的第4行(keydev.tail != keydev.head)就可以得到满足,从而执行第8行的copy_to_user()将按键事件拷贝给用户。

关于s3c2410按键驱动的问题

03-08

按键是低电平触发,如何修改代码变成高电平触发rnrn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rnrn#include "demo.h"rnrnMODULE_AUTHOR("fgj");rnMODULE_LICENSE("Dual BSD/GPL");rnstatic struct class *button_class;rnstatic int irqArray[4]=rnrn IRQ_EINT0,rn IRQ_EINT2,rn IRQ_EINT11,rn IRQ_EINT19rn;rnstruct DEMO_dev *DEMO_devices;rnstatic unsigned char demo_inc=0;rnstatic int flag = 0;rnstruct timer_list polling_timer;rnstatic unsigned long polling_jffs=0;rnvoid initButton(void)rnrn writel((readl(S3C2410_GPGCON)&(~((3<<22)|(3<<6))))|((2<<22)|(2<<6)),S3C2410_GPGCON); //GPG11,3 set EINTrn writel((readl(S3C2410_GPFCON)&(~((3<<4)|(3<<0))))|((2<<4)|(2<<0)),S3C2410_GPFCON) ; //GPF2,0 set EINTrnrn writel((readl(S3C2410_EXTINT0)&(~(7|(7<<8)))),S3C2410_EXTINT0);rn writel((readl(S3C2410_EXTINT0)|(0|(0<<8))),S3C2410_EXTINT0); //set eint0,2 falling edge intrn writel((readl(S3C2410_EXTINT1)&(~(7<<12))),S3C2410_EXTINT1);rn writel((readl(S3C2410_EXTINT1)|(0<<12)),S3C2410_EXTINT1); //set eint11 falling edge intrn writel((readl(S3C2410_EXTINT2)&(~(0xf<<12))),S3C2410_EXTINT2);rn writel((readl(S3C2410_EXTINT2)|(0<<12)),S3C2410_EXTINT2); //set eint19 falling edge intrnrn writel((readl(S3C2410_GPECON)&(~((3<<22)|(3<<26)))),S3C2410_GPECON);rn writel((readl(S3C2410_GPECON)|(((1<<22)|(1<<26)))),S3C2410_GPECON);rn writel((readl(S3C2410_GPEUP)|(1<<11)|(1<<13)),S3C2410_GPEUP);rn writel((readl(S3C2410_GPEDAT)&(~((1<<11)|(1<<13)))),S3C2410_GPEDAT);rn writel((readl(S3C2410_EINTPEND)|((1<<11)|(1<<19))),S3C2410_EINTPEND); //clear eint 11,19rn writel((readl(S3C2410_EINTMASK)&(~((1<<11)|(1<<19)))),S3C2410_EINTMASK); //enable eint11,19*/rnrnrnvoid polling_handler(unsigned long data)rnrn int code=-1;rn //writel(readl(S3C2410_SRCPND)&0xffffffda,S3C2410_SRCPND);//clear srcpnd 0 2 11 19rn //mdelay(1);rn //扫描按键表,根据中断号,找出所按下的按键。rn //writel(readl(S3C2410_GPEDAT)|0x2000,S3C2410_GPEDAT);//set GPE11 13 to 10rn //writel(readl(S3C2410_GPEDAT)&0xfffff7ff,S3C2410_GPEDAT);//...rn if( (readl(S3C2410_GPGDAT)&(1<<11)) == 0 )rn rn code=6;rn goto IRQ_OUT;rn rnIRQ_OUT:rn enable_irq(IRQ_EINT0);rn enable_irq(IRQ_EINT2);rn enable_irq(IRQ_EINT11);rn enable_irq(IRQ_EINT19);rnrn if(code>=0)rn rn //避免中断连续出现rn if((jiffies-polling_jffs)>100)rn rn polling_jffs=jiffies;rn //获取键盘值rn DEMO_devices->key=code;rn printk("The light is very hight %d",DEMO_devices->key);rn flag = 1;rn wake_up_interruptible(&(DEMO_devices->wq));rn rn rn writel(readl(S3C2410_GPEDAT)&0xffffd7ff,S3C2410_GPEDAT);rnrnrnstatic irqreturn_t simplekey_interrupt(int irq, void *dummy, struct pt_regs *fp)rnrn disable_irq(IRQ_EINT0);rn disable_irq(IRQ_EINT2);rn disable_irq(IRQ_EINT11);rn disable_irq(IRQ_EINT19);rnrn polling_timer.expires = jiffies + HZ/5;rn add_timer(&polling_timer);rnrn return IRQ_HANDLED;rnrnrnint DEMO_open(struct inode *inode, struct file *filp)rnrn struct DEMO_dev *dev;rnrn if(demo_inc>0)return -ERESTARTSYS;rn demo_inc++;rnrn dev = container_of(inode->i_cdev, struct DEMO_dev, cdev);rn filp->private_data = dev;rn return 0;rnrnrnint DEMO_release(struct inode *inode, struct file *filp)rnrn demo_inc--;rn return 0;rnrnrnssize_t DEMO_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos)rnrn struct DEMO_dev *dev = filp->private_data; rn int sum=0;rn if(flag==1)rn rn flag = 0;rn sum=1;rn if (copy_to_user(buf,&dev->key,1))rn rn sum=-EFAULT; rn rn rn elsern rn if (filp->f_flags & O_NONBLOCK)rn rn return -EAGAIN;rn rn elsern rn if(wait_event_interruptible(dev->wq, flag != 0))rn rn return - ERESTARTSYS;rn rn flag = 0;rn sum=1;rn if (copy_to_user(buf,&dev->key,1))rn rn sum=-EFAULT; rn rn rn rn return sum;rnrnunsigned int DEMO_poll(struct file *filp, poll_table *wait)rnrn struct DEMO_dev *dev = filp->private_data; rn poll_wait(filp, &dev->wq, wait);rn if (flag==1)//数据准备好rn return POLLIN | POLLRDNORM;rn return 0;rnrnrnstruct file_operations DEMO_fops = rn .owner = THIS_MODULE,rn .read = DEMO_read,rn .open = DEMO_open,rn .poll= DEMO_poll,rn .release = DEMO_release,rn;rnrn/*******************************************************rn MODULE ROUTINErn*******************************************************/rnvoid DEMO_cleanup_module(void)rnrn dev_t devno = MKDEV(DEMO_MAJOR, DEMO_MINOR);rn int i;rn for (i = 0; i <4; i++) rn free_irq(irqArray[i],simplekey_interrupt);rn rn if (DEMO_devices) rn rn cdev_del(&DEMO_devices->cdev);rn kfree(DEMO_devices);rn rn unregister_chrdev_region(devno,1);rn class_destroy(button_class);rnrnrnint DEMO_init_module(void)rnrn int result;rn dev_t dev = 0;rn int i=0;rn initButton();rn dev = MKDEV(DEMO_MAJOR, DEMO_MINOR);rn result = register_chrdev_region(dev, 1, "KEY");rn if (result < 0) rn rn printk(KERN_WARNING "DEMO: can't get major %d\n", DEMO_MAJOR);rn return result;rn rnrn DEMO_devices = kmalloc(sizeof(struct DEMO_dev), GFP_KERNEL);rn if (!DEMO_devices)rn rn result = -ENOMEM;rn goto fail;rn rn memset(DEMO_devices, 0, sizeof(struct DEMO_dev));rnrn init_MUTEX(&DEMO_devices->sem);rn cdev_init(&DEMO_devices->cdev, &DEMO_fops);rn DEMO_devices->cdev.owner = THIS_MODULE;rn DEMO_devices->cdev.ops = &DEMO_fops;rn result = cdev_add (&DEMO_devices->cdev, dev, 1);rn if(result)rn rn printk(KERN_NOTICE "Error %d adding DEMO\n", result);rn goto fail;rn rnrn for (i = 0; i <4; i++) rn if (request_irq(irqArray[i], &simplekey_interrupt, SA_INTERRUPT, "simplekey", NULL)) rn printk("request button irq failed!\n");rn return -1;rn rn rn button_class=class_create(THIS_MODULE,"/dev/KEY");rn class_device_create(button_class,NULL,MKDEV(DEMO_MAJOR,0),NULL,"/dev/KEY"); rn init_waitqueue_head(&DEMO_devices->wq);rn init_timer(&polling_timer);rn polling_timer.data = (unsigned long)0;rn polling_timer.function = polling_handler;rn return 0;rnrnfail:rn DEMO_cleanup_module();rn return result;rnrnrnmodule_init(DEMO_init_module);rnmodule_exit(DEMO_cleanup_module); 论坛

关于简单的按键驱动 请教

08-20

[code=C/C++]rn//头文件rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn#include rn rnrn#define DEVICE_NAME "menu_test"rn//#define IRQ_NO (IRQ_EINT(16))rnstruct menu_dev rn struct cdev cdev;rn;rnstruct menu_dev *menu_devp;//设备结构体指针rnint IRQ_NO;//定义中断号rnrn//函数声明rnstatic int menu_major = 250;rnstatic void menu_setup_cdev(struct menu_dev * , int );rnstatic int menu_init(void);rnstatic int menu_open(struct inode * , struct file *);rnstatic int menu_release(struct inode * ,struct file *);rnstatic void init_gpio(void);rnrn//中断处理函数rnirqreturn_t menu_interrupt(int irq, void *dev_id)rnrn printk("menu_interrupt start.....!\n");rn disable_irq_nosync(irq);//关中断rn udelay(5);//延迟5ms,消除毛刺信号rn printk("i am interrup handler\n");rn init_gpio();rn enable_irq(irq);//开中断rn printk("menu_interrupt over.......!\n");rn return IRQ_HANDLED;rnrnrn//初始化配置函数rnstatic void init_gpio(void)rnrn int error;rn printk("init_gpio start....\n");rn rn error = gpio_request(S5PV210_GPH2(0),"gpio_keys");//检查gpio管脚是否被使用rn if (error < 0) rn printk("gpio-keys: failed to request GPIO %d \n", S5PV210_GPH2(0));rn else rn printk("gpio %d success!\n",S5PV210_GPH2(0));rn s3c_gpio_cfgpin(S5PV210_GPH2(0),0xf); //将管脚配置为中断模式rnrn IRQ_NO = gpio_to_irq(S5PV210_GPH2(0));//获取中断号,其实这个我也不太清楚,看别人的。rn if (error < 0) rn printk("gpio_to_irq: failed %d \n", S5PV210_GPH2(0));rn else rn printk("gpio_to_irq %d success!\n",S5PV210_GPH2(0));rnrn //配置为输出 且为低电平rn s3c_gpio_cfgpin(S5PV210_GPH3(0),S3C_GPIO_OUTPUT);//配置为输出,低电平 EINT24号管脚 参照原理图上的。rn s3c_gpio_setpin(S5PV210_GPH3(0),1);rn rn s3c_gpio_cfgpin(S5PV210_GPH3(1),S3C_GPIO_OUTPUT);//配置为输出,低电平 EINT25号管脚rn s3c_gpio_setpin(S5PV210_GPH3(1),1); rnrn //设置下降沿触发rn set_irq_type(IRQ_NO,IRQ_TYPE_EDGE_FALLING); rn printk("init_gpio successed!\n");rnrnrnstatic int menu_open(struct inode *inode , struct file *filp)rnrn rn int ret;rn init_gpio();//对相关端口初始化rn rn ret = request_irq(IRQ_NO, menu_interrupt, IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, DEVICE_NAME, NULL);rn if(ret < 0)rn printk("request_irq failer\n");rn return -EFAULT;rn rn else rn printk("request_irq success !\n"); rn return ret;rnrnstatic int menu_release(struct inode *inode ,struct file *filp)rnrn printk("this is release\n");rn free_irq(IRQ_NO,NULL); rn return 0;rnrnrnrnrnstatic struct file_operations menu_fops = rn .owner = THIS_MODULE,rn .open = menu_open,rn .release = menu_release,rn;rnstatic void menu_setup_cdev(struct menu_dev *dev, int minor)rnrn int err;rn int devno = MKDEV(menu_major,minor);rn cdev_init(&dev->cdev,&menu_fops);rn dev -> cdev.owner = THIS_MODULE;rn err = cdev_add(&dev->cdev, devno, 1);rn if(err)rn printk("error %d adding menu %d \n",err,minor); rn rn printk("menu_setup_cdev over!\n");rnrnrnstatic int menu_init(void)rnrn int ret = 0;rn dev_t dev = MKDEV(menu_major , 0);rn if(menu_major)rn ret = register_chrdev_region(dev, 1, DEVICE_NAME);rn elsern ret = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);rn menu_major = MAJOR(dev); rn rn if(ret < 0)rn printk("unable to get major %d \n",menu_major);rn return ret; rn rn menu_devp = kmalloc(sizeof(struct menu_dev),GFP_KERNEL);rn if(!menu_devp)rn rn ret = -ENOMEM;rn rn memset(menu_devp,0,sizeof(struct menu_dev));rn menu_setup_cdev(menu_devp, 0 );rn printk("menu driver initialized\n");rn return 0; rnrnrnrn//驱动卸载rnvoid menu_exit(void)rnrn cdev_del(&menu_devp->cdev);rn unregister_chrdev_region(MKDEV(menu_major,0),1);rn printk("menu driver unistalled \n");rnrnrnmodule_init(menu_init);rnmodule_exit(menu_exit);rnrnMODULE_LICENSE("Dual BSD/GPL");rnrn[/code] 论坛

没有更多推荐了,返回首页