使用定时器或底半部延时工作队列
按下去抖的-代码示例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <mach/platform.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
struct cdev btn_cdev;
dev_t dev;
struct class *cls;
/*定义一个信号量*/
struct semaphore btn_sem;
/*定义按键键值缓冲区*/
unsigned char key_buf;
/*表示按键缓冲区中是否有键值 0,无键值 1,有键值*/
volatile unsigned int ev_press = 0;
/*定义一个等待队列头*/
wait_queue_head_t btn_wqh;
typedef struct btn_desc
{
unsigned char code;//按键编码值
int irq;
char *name;
}btn_desc_t;
btn_desc_t buttons[]=
{
{0x10, IRQ_GPIO_A_START+28, "up"},
{0x20, IRQ_GPIO_B_START+30, "down"},
{0x30, IRQ_GPIO_B_START+31, "left"},
{0x40, IRQ_GPIO_B_START+9, "right"},
};
struct timer_list btn_timer;//延时去抖
int btn_open(struct inode *inode, struct file *filp)
{
/*获取信号量*/
//down(&btn_sem);
if(down_interruptible(&btn_sem))
{
return -ERESTARTSYS;
}
return 0;
}
int btn_close(struct inode *inode, struct file *filp)
{
up(&btn_sem);
return 0;
}
ssize_t btn_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
{
int ret = 0;
/*有数据就直接返回给用户空间 无数据就睡眠等待
*等待过程中一旦有数据可供用户空间读,就唤醒睡眠进程
*将数据返回到用户空间
* */
wait_event_interruptible(btn_wqh, ev_press);
/*将键值拷贝到用户空间内存*/
ret = copy_to_user(buf, &key_buf, len);
ev_press = 0;
return len;
}
struct file_operations btn_fops =
{
.owner = THIS_MODULE,
.open = btn_open,
.release = btn_close,
.read = btn_read,
};
irqreturn_t btn_isr(int irq, void *dev)
{
/*传递了按键的描述信息*/
btn_timer.data = (unsigned long)dev;
/*修改定时器的超时时间*/
mod_timer(&btn_timer, jiffies+HZ/100);
return IRQ_HANDLED;
}
void btn_timer_func(unsigned long data)
{
/*获取哪个按键触发*/
btn_desc_t *pdata = (btn_desc_t *)data;
/*保存按键值*/
key_buf = pdata->code;
ev_press = 1;//按键缓冲区中有键值
/*唤醒因无键值而睡眠的进程*/
wake_up_interruptible(&btn_wqh);
}
int __init btn_drv_init(void)
{
int ret = 0;
int i = 0;
/*申请设备号*/
alloc_chrdev_region(&dev, 0, 1, "mybuttons");
/*初始化cdev*/
cdev_init(&btn_cdev, &btn_fops);
/*注册cdev*/
cdev_add(&btn_cdev, dev, 1);
/*创建设备文件*/
cls = class_create(THIS_MODULE, "buttons");
device_create(cls, NULL, dev, NULL, "mybuttons");
/*初始化信号量*/
sema_init(&btn_sem, 1);
/*初始化等待队列头*/
init_waitqueue_head(&btn_wqh);
/*注册中断*/
for(; i<ARRAY_SIZE(buttons); i++)
{
ret = request_irq(buttons[i].irq, btn_isr, IRQF_TRIGGER_FALLING,
buttons[i].name, buttons+i);
}
/*初始化timer*/
init_timer(&btn_timer);
btn_timer.function = btn_timer_func;
return 0;
}
void __exit btn_drv_exit(void)
{
int i = 0;
/*停止定时器*/
del_timer(&btn_timer);
for(; i<ARRAY_SIZE(buttons); i++)
{
/*注销中断*/
free_irq(buttons[i].irq, buttons+i);
}
/*销毁设备文件*/
device_destroy(cls, dev);
class_destroy(cls);
/*注销cdev*/
cdev_del(&btn_cdev);
/*注销设备号*/
unregister_chrdev_region(dev, 1);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);
按键的按下和释放都去抖-代码示例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <mach/platform.h>
#include <linux/sched.h>
#include <linux/gpio.h>
MODULE_LICENSE("GPL");
struct cdev btn_cdev;
dev_t dev;
struct class *cls;
/*定义一个信号量*/
struct semaphore btn_sem;
/*定义按键键值缓冲区*/
unsigned char key_buf;
/*表示按键缓冲区中是否有键值 0,无键值 1,有键值*/
volatile unsigned int ev_press = 0;
/*定义一个等待队列头*/
wait_queue_head_t btn_wqh;
typedef struct btn_desc
{
unsigned char code;//按键编码值
int irq;
char *name;
int gpio;//管脚编号
}btn_desc_t;
btn_desc_t buttons[]=
{
{0x10, IRQ_GPIO_A_START+28, "up", PAD_GPIO_A+28},
{0x20, IRQ_GPIO_B_START+30, "down", PAD_GPIO_B+30},
{0x30, IRQ_GPIO_B_START+31, "left", PAD_GPIO_B+31},
{0x40, IRQ_GPIO_B_START+9, "right", PAD_GPIO_B+9},
};
struct timer_list btn_timer;//延时去抖
int btn_open(struct inode *inode, struct file *filp)
{
/*获取信号量*/
//down(&btn_sem);
if(down_interruptible(&btn_sem))
{
return -ERESTARTSYS;
}
return 0;
}
int btn_close(struct inode *inode, struct file *filp)
{
up(&btn_sem);
return 0;
}
ssize_t btn_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
{
int ret = 0;
/*有数据就直接返回给用户空间 无数据就睡眠等待
*等待过程中一旦有数据可供用户空间读,就唤醒睡眠进程
*将数据返回到用户空间
* */
wait_event_interruptible(btn_wqh, ev_press);
/*将键值拷贝到用户空间内存*/
ret = copy_to_user(buf, &key_buf, len);
ev_press = 0;
return len;
}
struct file_operations btn_fops =
{
.owner = THIS_MODULE,
.open = btn_open,
.release = btn_close,
.read = btn_read,
};
irqreturn_t btn_isr(int irq, void *dev)
{
/*传递了按键的描述信息*/
btn_timer.data = (unsigned long)dev;
/*修改定时器的超时时间*/
mod_timer(&btn_timer, jiffies+HZ/100);
return IRQ_HANDLED;
}
void btn_timer_func(unsigned long data)
{
int stat = 0;
/*获取哪个按键触发*/
btn_desc_t *pdata = (btn_desc_t *)data;
stat = gpio_get_value(pdata->gpio);
/*保存按键值*/
key_buf = pdata->code + stat;
ev_press = 1;//按键缓冲区中有键值
/*唤醒因无键值而睡眠的进程*/
wake_up_interruptible(&btn_wqh);
}
int __init btn_drv_init(void)
{
int ret = 0;
int i = 0;
/*申请设备号*/
alloc_chrdev_region(&dev, 0, 1, "mybuttons");
/*初始化cdev*/
cdev_init(&btn_cdev, &btn_fops);
/*注册cdev*/
cdev_add(&btn_cdev, dev, 1);
/*创建设备文件*/
cls = class_create(THIS_MODULE, "buttons");
device_create(cls, NULL, dev, NULL, "mybuttons");
/*初始化信号量*/
sema_init(&btn_sem, 1);
/*初始化等待队列头*/
init_waitqueue_head(&btn_wqh);
/*注册中断*/
for(; i<ARRAY_SIZE(buttons); i++)
{
ret = request_irq(buttons[i].irq, btn_isr,
IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,
buttons[i].name, buttons+i);
}
/*初始化timer*/
init_timer(&btn_timer);
btn_timer.function = btn_timer_func;
return 0;
}
void __exit btn_drv_exit(void)
{
int i = 0;
/*停止定时器*/
del_timer(&btn_timer);
for(; i<ARRAY_SIZE(buttons); i++)
{
/*注销中断*/
free_irq(buttons[i].irq, buttons+i);
}
/*销毁设备文件*/
device_destroy(cls, dev);
class_destroy(cls);
/*注销cdev*/
cdev_del(&btn_cdev);
/*注销设备号*/
unregister_chrdev_region(dev, 1);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);