字符设备驱动程序之——定时器防抖动
按键操作过程中,会发生机械抖动,导致一次按键,产生多个中断。这样,一次按键就会返回多个按键值。为了消除这种机械抖动,我们选择使用定时器延时触发来忽略按键后瞬间的抖动。
一般情况下,按键机械抖动会在很短时间内结束。选择10ms延时处理即可消除大部分抖动。当第一个中断来到时,触发定时器工作,定时器计时10ms,然后再来处理这个中断。由于抖动,第二个中断产生,又会再次触发,这个会将之前的中断触发计时取消,重新计时10ms,以此类推。在10ms内,只有最后一个中断才能被执行。
代码如下:
1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/fs.h> 4 #include <linux/init.h> 5 #include <linux/delay.h> 6 #include <asm/uaccess.h> 7 #include <asm/irq.h> 8 #include <linux/irq.h> 9 #include <asm/irq_regs.h> 10 #include <asm/io.h> 11 #include <linux/device.h> 12 #include <mach/hardware.h> 13 #include <mach/regs-gpio.h> 14 #include <mach/gpio.h> 15 #include <linux/wait.h> 16 #include <linux/sched.h> 17 #include <linux/interrupt.h> 18 #include <linux/poll.h> 19 #include <linux/semaphore.h> 20 #include <linux/jiffies.h> 21 22 int major; 23 static struct class *sixthdrv_class; 24 static struct class *sixthdrv_class_dev; 25 volatile unsigned long *gpfcon ; 26 volatile unsigned long *gpfdat ; 27 volatile unsigned long *gpgcon ; 28 volatile unsigned long *gpgdat ; 29 static struct timer_list buttons_timer; 30 //static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量,初始化为1 31 static DEFINE_SEMAPHORE(button_lock); //定义互斥锁(定义向量) 32 static DECLARE_WAIT_QUEUE_HEAD(button_waitq); 33 /* 中断事件标志, 中断服务程序将它置1,sixth_drv_read将它清0 */ 34 static volatile int ev_press = 0; 35 static struct fasync_struct *button_async; 36 struct pin_desc{ 37 unsigned int pin; 38 unsigned int key_val; 39 }; 40 /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */ 41 /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */ 42 static unsigned char key_val; 43 struct pin_desc pins_desc[4] = { 44 { S3C2410_GPF(0), 0x01 }, 45 { S3C2410_GPF(2), 0x02 }, 46 { S3C2410_GPG(3), 0x03 }, 47 { S3C2410_GPG(11), 0x04 } 48 }; 49 static struct pin_desc *irq_pd ; 50 /* 51 * 确定按键值 52 */ 53 static irqreturn_t bottons_irq(int irq, void *dev_id) 54 { 55 irq_pd = (struct pin_desc * )dev_id; 56 /*修改定时器超时值*/ 57 mod_timer(&buttons_timer,jiffies + HZ/100 ); //jiffies当前值,HZ/100=10ms 58 return IRQ_RETVAL(IRQ_HANDLED); 59 } 60 static void buttons_timer_function(unsigned long data) 61 { 62 struct pin_desc * pindesc = irq_pd; 63 unsigned int pinval; 64 if(!pindesc) 65 return; 66 pinval = s3c2410_gpio_getpin( pindesc->pin ); 67 if (!pinval) 68 { 69 /* 按下 */ 70 key_val = pindesc->key_val; 71 } 72 else 73 { 74 /* 松开 */ 75 key_val = 0x80 | pindesc->key_val; 76 } 77 ev_press = 1; /* 设置中断标志,不再休眠*/ 78 kill_fasync(&button_async, SIGIO, POLL_IN); 79 wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */ 80 } 81 static int sixth_drv_open(struct inode *inode,struct file *file) 82 { 83 #if 0 /*原子操作法*/ 84 if (!atomic_dec_and_test(&canopen)) 85 { 86 atomic_inc(&canopen); 87 return -EBUSY; 88 } 89 #endif 90 if (file->f_flags & O_NONBLOCK) //判断是否是"非阻塞" 91 { 92 if(down_trylock(&button_lock)) //无法获得信号量,立马返回,不休眠等待 93 return -EBUSY; 94 } 95 else //"阻塞操作" 96 { 97 down(&button_lock); //获取信号量 98 } 99 /* 设置中断*/ 100 request_irq(IRQ_EINT0, bottons_irq, IRQ_TYPE_EDGE_BOTH, "s2", &pins_desc[0] ); 101 request_irq(IRQ_EINT2, bottons_irq, IRQ_TYPE_EDGE_BOTH, "s3", &pins_desc[1] ); 102 request_irq(IRQ_EINT11, bottons_irq, IRQ_TYPE_EDGE_BOTH, "s4", &pins_desc[2] ); 103 request_irq(IRQ_EINT19, bottons_irq, IRQ_TYPE_EDGE_BOTH, "s5", &pins_desc[3] ); 104 return 0; 105 } 106 static ssize_t sixth_drv_read(struct file *file, char __user *buf,size_t size, loff_t *ppos) 107 { 108 if(size != 1) //判断 109 return -EINVAL; 110 if (file->f_flags & O_NONBLOCK) //非阻塞 111 { 112 if (!ev_press) //没有按键动作 113 return -EAGAIN; 114 } 115 else /* 如果没有按键动作, 休眠 */ 116 { 117 wait_event_interruptible(button_waitq, ev_press); 118 } 119 /* 如果有按键动作, 返回键值 */ 120 copy_to_user(buf,&key_val,1); 121 ev_press = 0; 122 return 1; 123 } 124 sixth_drv_close(struct inode * inode,struct file * file) 125 { 126 //atomic_inc(&canopen); //关闭前,将变量自加还原为1 127 free_irq(IRQ_EINT0 ,&pins_desc[0]); 128 free_irq(IRQ_EINT2 ,&pins_desc[1]); 129 free_irq(IRQ_EINT11 ,&pins_desc[2]); 130 free_irq(IRQ_EINT19 ,&pins_desc[3]); 131 up(&button_lock); 132 return 0; 133 } 134 static unsigned int sixth_drv_poll(struct file *file, poll_table *wait) 135 { 136 unsigned int mask = 0; 137 poll_wait(file, &button_waitq, wait); 138 if (ev_press) 139 mask |= POLLIN | POLLRDNORM; 140 return mask; 141 } 142 static int sixth_drv_fasync(int fd, struct file *filp, int on) 143 { 144 return fasync_helper(fd, filp, on, &button_async); 145 } 146 /* 这个结构是字符设备驱动程序的核心 147 * 当应用程序操作设备文件时所调用的open、read、write等函数, 148 * 最终会调用这个结构中指定的对应函数 149 */ 150 static struct file_operations sixth_drv_fops = { 151 .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ 152 .open = sixth_drv_open, 153 .read = sixth_drv_read, 154 .release = sixth_drv_close, 155 .poll = sixth_drv_poll, 156 .fasync = sixth_drv_fasync, 157 }; 158 int sixth_drv_init(void) 159 { 160 major = register_chrdev(0,"sixth_drv",&sixth_drv_fops); //注册,告诉内核 161 init_timer(&buttons_timer); /*初始化定时器*/ 162 buttons_timer.function = buttons_timer_function; 163 //buttons_timer.expires =0 ; 164 add_timer(&buttons_timer); 165 sixthdrv_class = class_create(THIS_MODULE, "sixthdrv"); 166 sixthdrv_class_dev = device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/button */ 167 gpfcon=(volatile unsigned long)ioremap(0x56000050,16);//gpio 映射 168 gpfdat=gpfcon+1; 169 gpgcon=(volatile unsigned long)ioremap(0x56000060,16);//gpio 映射 170 gpgdat=gpgcon+1; 171 return 0; 172 } 173 void sixth_drv_exit(void) 174 { 175 unregister_chrdev(major,"sixth_drv"); //卸载,告诉内核 176 device_destroy(sixthdrv_class, MKDEV(major, 0)); 177 class_destroy(sixthdrv_class); 178 iounmap(gpfcon); 179 iounmap(gpgcon); 180 } 181 module_init(sixth_drv_init); 182 module_exit(sixth_drv_exit); 183 MODULE_LICENSE("GPL");
测试程序:
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <stdio.h> 5 #include <poll.h> 6 #include <signal.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 /* buttonsdrvtest 10 * 11 */ 12 int fd; 13 #if 0 14 void my_signal_fun(int signum) 15 { 16 unsigned char key_val; 17 read(fd, &key_val,1); 18 printf("key_val = 0x%x\n", key_val); 19 } 20 #endif 21 int main(int argc, char **argv) 22 { 23 int ret; 24 int Oflags; 25 unsigned char key_val; 26 struct pollfd fds[1]; 27 28 fd = open("/dev/buttons", O_RDWR); //阻塞格式 29 // fd = open("/dev/buttons", O_RDWR | O_NONBLOCK); //非阻塞格式 30 if (fd < 0) 31 { 32 printf("can't open!\n"); 33 return -1 ; 34 } 35 // signal(SIGIO,my_signal_fun); 36 // fcntl(fd, F_SETOWN, getpid()); 37 // Oflags = fcntl(fd, F_GETFL); 38 // fcntl(fd, F_SETFL, Oflags | FASYNC); 39 while(1) 40 { 41 ret = read(fd, &key_val,1); 42 printf("key_val = 0x%x,ret = %d\n", key_val,ret); 43 key_val = 0; 44 //sleep(5); 45 } 46 return 0; 47 }
总结:按键时,发生中断,调用 irqreturn_t bottons_irq ,mod_timer设置定时器超时时间10ms,10ms后再调用buttons_timer_function,进行按键操作处理。
浙公网安备 33010602011771号