嵌入式Linux驱动学习之路(十五)按键驱动-定时器防抖
生活随笔
收集整理的這篇文章主要介紹了
嵌入式Linux驱动学习之路(十五)按键驱动-定时器防抖
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在之前的定時器驅動程序中,我們發現在連續按下按鍵的時候,正常情況下應該是一次按下對應一次松開。而程序有時候會顯示是兩次按下,一次松開。這個問題是因為在按下的時候,因為是機械按鍵,所以電壓信號會產生一定的波動,會讓程序進行兩次中斷,如何解決這個問題呢?
我們可以在發生一次中斷之后等待一段時間再去判斷按鍵是否已經被按下,如果是已經被按下了 則本次有效,否則無效。這里用到了定時器。
定時器常用的操作函數有:
init_timer(&timer); ? //定時器初始化timer.data=10; ? ? ? ? //設置超時處理函數參數timer.expires=jiffies+(10*HZ); ? //設置超時jiffies值為10s ?timer.function=timer_func;? //設置超時處理函數add_timer(&timer); ? ? ? //添加定時器到內核del_timer(&timer); ? //刪除定時器 在每次調用之前應該把上次調用的刪除?
驅動代碼:
#include <linux/sched.h> #include <linux/signal.h> #include <linux/spinlock.h> #include <linux/errno.h> #include <linux/random.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/wait.h> #include <linux/mutex.h> #include <linux/io.h> #include <asm/irq.h> #include <linux/irq.h> #include <linux/fs.h> #include <asm/arch/regs-gpio.h> #include <linux/interrupt.h> #include <linux/poll.h>static struct class *key_class; //創建類 static struct class_device *key_class_devs; //創建類對應的設備 static struct timer_list keys_timer;struct pin_desc{unsigned int pin;unsigned int key_val; }; struct pin_desc pins_desc[4] = {{S3C2410_GPF0,0X01},{S3C2410_GPF2,0X02},{S3C2410_GPG3,0X03},{S3C2410_GPG11,0X04}, };struct pin_desc *pin_timer; //在按鍵中斷里保存按下按鍵的信息 unsigned char keyvals=0;static volatile int ev_press = 0; static DECLARE_WAIT_QUEUE_HEAD(button_waitq);static struct fasync_struct *key_async_queue;static DECLARE_MUTEX(canopen); //定義互斥鎖static irqreturn_t keys_irq(int irq, void *dev_id) {pin_timer = (struct pin_desc *)dev_id;mod_timer(&keys_timer, jiffies+HZ/100 ); //jiffies是個全局變量,每10ms累加一次,這里是10ms產生一次中斷return IRQ_HANDLED; }int key_open(struct inode *inode, struct file *fp) {/*獲取信號量*/if( fp->f_flags & O_NONBLOCK ){if(down_trylock(&canopen))return -EBUSY;}else{down(&canopen);}request_irq( IRQ_EINT0, keys_irq, IRQT_BOTHEDGE, "key2", &pins_desc[0]);request_irq( IRQ_EINT2, keys_irq, IRQT_BOTHEDGE, "key3", &pins_desc[1]);request_irq( IRQ_EINT11, keys_irq, IRQT_BOTHEDGE, "key4", &pins_desc[2]);request_irq( IRQ_EINT19, keys_irq, IRQT_BOTHEDGE, "key5", &pins_desc[3]);return 0; }ssize_t key_read(struct file *fp, char __user *buff, size_t count, loff_t *offp){if(fp->f_flags & O_NONBLOCK ){if(!ev_press)return -EAGAIN;}else{wait_event_interruptible(button_waitq,ev_press);}if(count != 1){return -EINVAL;}copy_to_user(buff,&keyvals,1);ev_press = 0;return 0; }ssize_t key_write(struct file *fp, const char __user *buf, size_t count, loff_t *ppos){ }int key_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(&canopen); }static unsigned int key_poll(struct file *file, struct poll_table_struct *wait) {unsigned int mask = 0;poll_wait(file, &button_waitq,wait);if(ev_press)mask |= POLLIN|POLLRDNORM;return mask; }static int key_fsync (int fd, struct file *filp, int on) {printk("ok\n");return fasync_helper (fd, filp, on, &key_async_queue); }struct file_operations led_fops={.owner = THIS_MODULE,.open = key_open,.write = key_write,.read = key_read,.release = key_close,.poll = key_poll,.fasync = key_fsync, };static void keys_timer_fun(unsigned long t) {struct pin_desc *pindesc = (struct pin_desc *)pin_timer;unsigned int pinval;if( !pindesc )return ;pinval = s3c2410_gpio_getpin(pindesc->pin);if(pinval){keyvals = pindesc->key_val|0x80;}else{keyvals = pindesc->key_val;}ev_press = 1;wake_up_interruptible(&button_waitq);kill_fasync (&key_async_queue, SIGIO, POLL_IN);return ; }int major; static int key_init(void) {major = register_chrdev( 0,"key_drv", &led_fops );key_class = class_create(THIS_MODULE,"key_class");key_class_devs = class_device_create(key_class,NULL,MKDEV(major,0),NULL,"my_keys");init_timer(&keys_timer);keys_timer.function = keys_timer_fun; /*定時器中斷函數*/keys_timer.expires = 0;add_timer(&keys_timer);printk("key install Module\n");return 0; }static void key_exit(void) {unregister_chrdev( major, "key_drv" );class_device_unregister(key_class_devs);class_destroy(key_class);del_timer(&keys_timer); //刪除定時器printk("key Module exit\n"); }module_init(key_init); module_exit(key_exit); MODULE_LICENSE("GPL");
測試應用程序:
#include <stdio.h> #include <signal.h> #include <fcntl.h> #include <unistd.h> int fd; static char key_val; int main( int argc, char **argv ) {int oflags;fd = open("/dev/my_keys",O_RDWR);/* O_NONBLOCK為非阻塞*/if(fd<0){printf("open failed\n");return 0;}while(1){read(fd,&key_val,1);printf("key_val:%d\n",key_val);}return 0; }?
?
sd
轉載于:https://www.cnblogs.com/ynxf/p/6002709.html
總結
以上是生活随笔為你收集整理的嵌入式Linux驱动学习之路(十五)按键驱动-定时器防抖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UIAlertController 大坑
- 下一篇: 类的加载次序与继承