在测试按键驱动时,可能会出现按键抖动的问题,也就是按下或松开一次,却进入了多次中断程序。如下图所示:
产生这个问题是由于现实中的高电平转成低电平脉冲过程是机械式开关,可能会有机械的抖动导致多次触发中断
针对这个问题,我们可以采用延时检测来防止抖动,这就是这节要讲解的内核定时器,内核定时器基于软中断,因此在处理函数中不允许睡眠
一、内核定时器的使用方法
定时器系列函数使用方法如下:
struct timer_list timer; // 定义定时器 init_timer(&timer); // 初始化定时器,初始化timer成员 timer.function = timer_func; // 设置定时器触发函数 或 setup_timer(&timer, timer_func, (unsigned long)arg); /* 函数参数中jiffies表示表示当前的系统时钟中断总次数 * 一秒内时钟中断的次数等于Hz * jiffies + HZ / 100表示此定时器的间隔时间为0.01秒,也就是10ms */ mod_timer(&timer, jiffies + HZ / 100); // 设置定时器间隔时间 add_timer(&timer); // 开始定时器 del_timer(&timer); // 删除定时器
代码中的timer_func()函数需要执行的就是之前的中断程序中的代码,现在的中断程序用于设置定时器间隔时间来进行延时操作
示例代码如下:
1 struct key_device { 2 ... 3 struct timer_list key_timer; // 定义定时器 4 }; 5 6 static void key_timer_func(unsigned long arg) 7 { 8 struct key_device* dev = (struct key_device *)arg; 9 ... /* 之前中断程序的代码 */ 10 } 11 12 static irqreturn_t key_interrupt(int irq, void *dev_id) 13 { 14 dev->pindesc = (struct pin_desc *)dev_id; 15 16 mod_timer(&dev->key_timer, jiffies + HZ / 100); // 设置延时 17 18 return IRQ_HANDLED; 19 } 20 21 static int key_open(struct inode *nodep, struct file *filp) 22 { 23 struct key_device *dev = container_of(nodep->i_cdev, struct key_device, cdev); 24 ... 25 26 init_timer(&dev->key_timer); // 初始化定时器,初始化timer成员 27 setup_timer(&dev->key_timer, key_timer_func, (unsigned long)dev); 28 add_timer(&dev->key_timer); // 启动定时器 29 30 return 0; 31 } 32 33 static int key_release(struct inode *nodep, struct file *filp) 34 { 35 struct key_device *dev = filp->private_data; 36 ... 37 del_timer(&dev->key_timer); // 删除定时器 38 }
示例代码中需要注意的是:在key_open()函数中并没有设置定时器的间隔时间,而是在中断中设置的
这是因为我们是在中断中设置延时防止抖动;在其他函数中并不需要延时,直接启动定时器即可
二、完整代码
点击查看:源代码
源代码中59、60行代码(如下),用于防止open()函数中add_timer()时进入timer函数
1 if (dev->pindesc == NULL) 2 return;
原文:https://www.cnblogs.com/Lioker/p/10863092.html