linux字符设备驱动-定时器按键去抖笔记
来源:互联网 发布:华为大数据 编辑:程序博客网 时间:2024/05/17 21:59
转自 http://blog.csdn.net/cs953575/article/details/62881986
一、开发环境
1、内核:Linux 2.6.22.6;
2、JZ2440
3、ubuntu 9.10
二、原理
机械按键按下时,弹片接触瞬间会使信号产生抖动,如果是使用中断读取按键值得话,则产生多次中断。使用定时器去抖的原理是,在按键中断函数里,初始化一个定时10ms(也可以是其他时间,一般10ms就可以了)的定时器函数。也就是说,这瞬间几次的中断都会使这个10ms的定时器初始化,重新定时10ms(这瞬间几次的中断时间间隔都是小于10ms的),直到最后一次按键中断不再使定时器初始化,可以顺利执行10ms的定时中断函数,在定时中断函数中我们把按键读出即可。这样就忽略掉了按键的前几次中断,只有最后一次中断有效了。
三、程序实现
1、定义timer_list结构体类型变量,如定义buttons_timer:static struct timer_list buttons_timer。这个结构体用于存放定时器的一些设置。
2、在驱动入口函数中增加
init_timer(&buttons_timer);//初始化定时器
buttons_timer.function = buttons_timer_function;//定时器函数,设置的时间到了的时候执行的函数。
//buttons_timer.expires = 0;
add_timer(&buttons_timer); //向内核注册定时器
3、编写buttons_timer_function函数。在里面添加定时时间到达时想执行的语句。如:
static void buttons_timer_function(unsigned long data)
{
......
}
4、设置定时器定时时间。使用函数mod_timer,如:mod_timer(&buttons_timer, jiffies+HZ/100);
buttons_timer上面定义的结构体。jiffies是一个只读变量,里面记录的是linux系统运行以来的滴答值,本系统每10ms加1,不同的cpu和系统jiffies加1的时间是不同的和具体设置有关;HZ是个常量为100,jiffies每秒增加100次。这样就可以基于jiffies,设置定时器在jiffies+HZ/100时执行上面的buttons_timer_function函数。jiffies+HZ/100=jiffies+1,比现在的jiffies值多1,也就是定时10ms。
5、韦源码如下:
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <linux/irq.h>
- #include <asm/uaccess.h>
- #include <asm/irq.h>
- #include <asm/io.h>
- #include <asm/arch/regs-gpio.h>
- #include <asm/hardware.h>
- #include <linux/poll.h>
-
-
- static struct class *sixthdrv_class;
- static struct class_device *sixthdrv_class_dev;
-
- volatile unsigned long *gpfcon;
- volatile unsigned long *gpfdat;
-
- volatile unsigned long *gpgcon;
- volatile unsigned long *gpgdat;
-
- static struct timer_list buttons_timer;
-
-
- static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
-
-
- static volatile int ev_press = 0;
-
- static struct fasync_struct *button_async;
-
-
- struct pin_desc{
- unsigned int pin;
- unsigned int key_val;
- };
-
-
-
-
- static unsigned char key_val;
-
- struct pin_desc pins_desc[4] = {
- {S3C2410_GPF0, 0x01},
- {S3C2410_GPF2, 0x02},
- {S3C2410_GPG3, 0x03},
- {S3C2410_GPG11, 0x04},
- };
-
- static struct pin_desc *irq_pd;
-
-
-
- static DECLARE_MUTEX(button_lock);
-
-
-
-
- static irqreturn_t buttons_irq(int irq, void *dev_id)
- {
-
- irq_pd = (struct pin_desc *)dev_id;
- mod_timer(&buttons_timer, jiffies+HZ/100);
- return IRQ_RETVAL(IRQ_HANDLED);
- }
-
- static int sixth_drv_open(struct inode *inode, struct file *file)
- {
- #if 0
- if (!atomic_dec_and_test(&canopen))
- {
- atomic_inc(&canopen);
- return -EBUSY;
- }
- #endif
-
- if (file->f_flags & O_NONBLOCK)
- {
- if (down_trylock(&button_lock))
- return -EBUSY;
- }
- else
- {
-
- down(&button_lock);
- }
-
-
-
- request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
- request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
- request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
- request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);
-
- return 0;
- }
-
- ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
- {
- if (size != 1)
- return -EINVAL;
-
- if (file->f_flags & O_NONBLOCK)
- {
- if (!ev_press)
- return -EAGAIN;
- }
- else
- {
-
- wait_event_interruptible(button_waitq, ev_press);
- }
-
-
- copy_to_user(buf, &key_val, 1);
- ev_press = 0;
-
- return 1;
- }
-
-
- int sixth_drv_close(struct inode *inode, struct file *file)
- {
-
- free_irq(IRQ_EINT0, &pins_desc[0]);
- free_irq(IRQ_EINT2, &pins_desc[1]);
- free_irq(IRQ_EINT11, &pins_desc[2]);
- free_irq(IRQ_EINT19, &pins_desc[3]);
- up(&button_lock);
- return 0;
- }
-
- static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
- {
- unsigned int mask = 0;
- poll_wait(file, &button_waitq, wait);
-
- if (ev_press)
- mask |= POLLIN | POLLRDNORM;
-
- return mask;
- }
-
- static int sixth_drv_fasync (int fd, struct file *filp, int on)
- {
- printk("driver: sixth_drv_fasync\n");
- return fasync_helper (fd, filp, on, &button_async);
- }
-
-
- static struct file_operations sencod_drv_fops = {
- .owner = THIS_MODULE,
- .open = sixth_drv_open,
- .read = sixth_drv_read,
- .release = sixth_drv_close,
- .poll = sixth_drv_poll,
- .fasync = sixth_drv_fasync,
- };
-
-
- int major;
-
- static void buttons_timer_function(unsigned long data)
- {
- struct pin_desc * pindesc = irq_pd;
- unsigned int pinval;
-
- if (!pindesc)
- return;
-
- pinval = s3c2410_gpio_getpin(pindesc->pin);
-
- if (pinval)
- {
-
- key_val = 0x80 | pindesc->key_val;
- }
- else
- {
-
- key_val = pindesc->key_val;
- }
-
- ev_press = 1;
- wake_up_interruptible(&button_waitq);
-
- kill_fasync (&button_async, SIGIO, POLL_IN);
- }
-
-
- static int sixth_drv_init(void)
- {
- init_timer(&buttons_timer);
- buttons_timer.function = buttons_timer_function;
-
- add_timer(&buttons_timer);
-
- major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);
-
- sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");
-
-
- sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons");
-
- gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
- gpfdat = gpfcon + 1;
-
- gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
- gpgdat = gpgcon + 1;
-
- return 0;
- }
-
- static void sixth_drv_exit(void)
- {
- unregister_chrdev(major, "sixth_drv");
- class_device_unregister(sixthdrv_class_dev);
- class_destroy(sixthdrv_class);
- iounmap(gpfcon);
- iounmap(gpgcon);
- return 0;
- }
-
-
- module_init(sixth_drv_init);
-
- module_exit(sixth_drv_exit);
-
- MODULE_LICENSE("GPL");
这里也有一个类似的案例
linux驱动程序之定时器防按键抖动
http://blog.csdn.net/tianzhihen_wq/article/details/42125377