In the previous timer driver, we found that in the continuous press of the button, it should normally be one time to press the corresponding release. The program sometimes shows that it is two times pressed and released at once. This problem is because when pressed, because it is a mechanical button, so the voltage signal will produce a certain fluctuation, will let the program two interrupts, how to solve this problem?
We can wait for a period of time after an interruption to determine whether the button has been pressed, if it has been pressed, this time is valid, otherwise invalid. The timer is used here.
The operation functions commonly used by timers are:
init_timer ( &timer); // timer initialization timer.data=10 ; // set timeout handler parameters &N bsp; timer.expires=jiffies+ (10 *hz); // set timeout jiffies value of 10s timer.function=timer_func; // Set the timeout handler add_timer (&timer); // add timer to kernel del_timer ( &timer); // Delete timer should delete the last call before each call
Driver Code:
#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;//Create ClassStatic structClass_device *key_class_devs;//Create a device for a classStatic structtimer_list Keys_timer;structpin_desc{unsignedintpin; unsignedintKey_val;};structPin_desc pins_desc[4] ={{s3c2410_gpf0,0x01}, {S3C2410_GPF2,0X02}, {s3c2410_gpg3,0X03}, {s3c2410_gpg11,0x04},};structPIN_DESC *Pin_timer; //Hold down the press key in the key interrupt unsignedCharkeyvals=0;Static volatile intEv_press =0;StaticDeclare_wait_queue_head (BUTTON_WAITQ);Static structFasync_struct *Key_async_queue;StaticDeclare_mutex (CANopen);//Defining Mutex LocksStaticIrqreturn_t KEYS_IRQ (intIrqvoid*dev_id) {Pin_timer= (structPIN_DESC *) dev_id; Mod_timer (&keys_timer, jiffies+hz/ - ); //jiffies is a global variable that accumulates every 10ms, where 10ms produces an interrupt returnirq_handled;}intKey_open (structInode *inode,structFile *FP) { /*get the Semaphore*/ 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 (structFile *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 (structFile *FP,Const Char__user *buf, size_t count, loff_t *PPOs) {}intKey_close (structInode *inode,structFile *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);}StaticUnsignedintKey_poll (structFile *file,structPoll_table_struct *wait) {unsignedintMask =0; Poll_wait (file,&button_waitq,wait); if(ev_press) Mask|= pollin|Pollrdnorm; returnMask;}Static intKey_fsync (intFdstructFile *filp,intOn ) {PRINTK ("ok\n"); returnFasync_helper (FD, Filp, ON, &key_async_queue);}structFile_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 voidKeys_timer_fun (unsignedLongt) { structPin_desc *pindesc = (structPIN_DESC *) Pin_timer; unsignedintPinval; 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 ;}intMajor;Static intKey_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; / * Timer Interrupt function * /keys_timer.expires=0; Add_timer (&Keys_timer); PRINTK ("Key Install module\n"); return 0;}Static voidKey_exit (void) {Unregister_chrdev (major,"Key_drv" ); Class_device_unregister (Key_class_devs); Class_destroy (Key_class); Del_timer (&Keys_timer); //Remove timer
PRINTK ("Key Module exit\n");} Module_init (Key_init); Module_exit (Key_exit); Module_license ("GPL");
To test the application:
#include <stdio.h>#include<signal.h>#include<fcntl.h>#include<unistd.h>intFD;Static CharKey_val;intMainintargcChar**argv) { intOflags; FD= Open ("/dev/my_keys", O_RDWR);/*O_nonblock for non-blocking*/ 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
Linux Embedded Drive Learning Path (15) key Driver-timer stabilization