您的位置:首页 > 运维架构 > Linux

linux字符设备按键驱动之防抖动

2013-06-30 15:21 447 查看
按键驱动程序抖动问题会造成多次中断发生,实则可能是一次按下或释放的操作。本驱动程序就是在按键驱动程序(中断方式)的基础之上,用定时器来去抖动。

当一次按键按下的时候,可能产生多个脉冲,我们可以等到最后一个脉冲平稳时再真正地做按下或释放的处理。所以,在中断中我们可以不断修改定时器的值,当最后稳定下来,没有中断产生了,就会调用超时函数,再在超时函数里面判断按键状态,返回值给用户空间等。
定时器的操作:
1.定义timer_list结构体。
2.定义超时函数。
3.在初始化函数绑定定时器结构体和超时函数,初始化定时器结构体等操作。用到
#define setup_timer(timer, fn, data) \

do { \

static struct lock_class_key __key; \

setup_timer_key((timer), #timer, &__key, (fn), (data));\

} while (0)
这个是在2.6.32内核里面进行的初始化设置,在低版本中可能包括init和add等操作。
4.在中断函数里修改定时器。用到
int mod_timer(struct timer_list *timer, unsigned long expires)

详细驱动程序如下:

#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 <linux/cdev.h>

#include <linux/interrupt.h>

#include <linux/device.h>

#include <linux/sched.h>

#include <linux/gpio.h>

#define SEVENTHDEV MKDEV(250, 0)

struct cdev seventhdrv_cdev;

static struct class
*seventhdrv_class;

struct button {

int irq;

char *name;

int pin;

int val;

};

static volatile int pressed
= 0;

static unsigned char key_val;

struct fasync_struct *button_async;

static struct timer_list seventh_timer;

static struct button *buttonp
= NULL;

DECLARE_WAIT_QUEUE_HEAD(button_wqh);

/* 六个按键的相关定义整合到结构体
*/

static struct button buttons[6]
= {

{IRQ_EINT8,
"K1", S3C2410_GPG(0), 0x1},

{IRQ_EINT11,
"K2", S3C2410_GPG(3), 0x2},

{IRQ_EINT13,
"K3", S3C2410_GPG(5), 0x3},

{IRQ_EINT14,
"K4", S3C2410_GPG(6), 0x4},

{IRQ_EINT15,
"K5", S3C2410_GPG(7), 0x5},

{IRQ_EINT19,
"K6", S3C2410_GPG(11),0x6},

};

static DECLARE_MUTEX(button_lock);

/* 中断处理函数
*/

static irqreturn_t seventhdrv_intr(int irq, void
*data)

{

buttonp = (struct button*)data;

mod_timer(&seventh_timer, jiffies+HZ/100);

return IRQ_RETVAL(IRQ_HANDLED);

}

static int seventhdrv_open(struct inode
* inode, struct file
* file)

{

int i=6;

if (file->f_flags
& O_NONBLOCK)
{

if(down_trylock(&button_lock))

return -EBUSY;

} else
{

down(&button_lock);

}

while(i--){

request_irq(buttons[i].irq,
&seventhdrv_intr, IRQ_TYPE_EDGE_BOTH,

buttons[i].name,
&buttons[i]);

}

return 0;

}

static ssize_t seventhdrv_read(struct file
*file, char __user
*user, size_t size,loff_t*o)

{

int sz = sizeof(key_val)
;

if (sz
!= size)
{

return -EINVAL;

}

if (file->f_flags
& O_NONBLOCK)

{

if (!pressed)

return -EAGAIN;

}

else

{

/* 如果没有按键动作, 休眠
*/

wait_event_interruptible(button_wqh, pressed);

}

copy_to_user(user,
&key_val, sz);

/* 重新清除按下标志
*/

pressed = 0;

return sz;

}

static int seventhdrv_close(struct inode
*inode, struct file
*file)

{

int i=6;

while(i--)
{

free_irq(buttons[i].irq,
&buttons[i]);

}

up(&button_lock);

return 0;

}

static struct file_operations seventhdrv_ops =
{

.owner = THIS_MODULE,

.open = seventhdrv_open,

.read = seventhdrv_read,

.release = seventhdrv_close,

};

static void button_timer(unsigned long data)

{

int val;

if (buttonp
==
NULL) {

printk(KERN_INFO
"No button pressed!\n");

return ;

}

val = s3c2410_gpio_getpin(buttonp->pin);

if (!val)
{/* 按下按键*/

key_val = buttonp->val;

} else
{ /* 释放按键*/

key_val = buttonp->val
| 0x10;
//将第4位置1,做标记

}

pressed = 1;
//此处改变按下标志,以使队列不继续睡眠

wake_up_interruptible(&button_wqh);

buttonp = NULL;

}

static int seventhdrv_init(void)

{

int ret;

int devt = SEVENTHDEV;

ret = register_chrdev_region(devt, 1,
"seventhdrv");

if (ret)
{

printk(KERN_ERR
"Unable to register minors for seventhdrv\n");

goto fail;

}

seventhdrv_class = class_create(THIS_MODULE,
"seventhdrv_class");

if (IS_ERR(seventhdrv_class))
{

printk(KERN_ERR
"can't register device class\n");

return PTR_ERR(seventhdrv_class);

}

device_create(seventhdrv_class,
NULL, devt,
NULL,
"buttons");

cdev_init(&seventhdrv_cdev,
&seventhdrv_ops);

ret = cdev_add(&seventhdrv_cdev, devt, 1);

if (ret
< 0)

goto fail_cdev;

setup_timer(&seventh_timer, button_timer,
(unsigned long)&buttons);

return 0;

fail_cdev:

class_unregister(seventhdrv_class);

device_destroy(seventhdrv_class, devt);

cdev_del(&seventhdrv_cdev);

fail:

unregister_chrdev_region(devt, 1);

return 0;

}

static void seventhdrv_exit(void)

{

class_unregister(seventhdrv_class);

device_destroy(seventhdrv_class, SEVENTHDEV);

cdev_del(&seventhdrv_cdev);

unregister_chrdev_region(SEVENTHDEV, 1);

}

module_init(seventhdrv_init);

module_exit(seventhdrv_exit);

MODULE_LICENSE("GPL");

应用程序为:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <signal.h>

int main(int argc, char
*argv[])

{

int fd, cnt=1;

unsigned char val;

fd = open("/dev/buttons", O_RDWR);

if (fd
< 0)

{

printf("Can not open device\n");

return -1;

}

while(1)

{

read(fd,
&val, sizeof(unsigned char));

printf("cnt:%d, val:0x%x\n", cnt++, val);

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: