01_使用定时器实现按键防抖
接着1-2期衔接课程的最后一节(阻塞方式),使用定时器来消除按键抖动的问题。
1、原理
2、程序思路
2.1、定义一个定时器
static struct timer_list buttons_timer;
2.2、发生中断时的引脚描述
static struct pin_desc *irq_pd;
2.3、在入口函数sixth_drv_init中
/* 1 初始化定时器 */
init_timer(&buttons_timer);
/* 2 定时器的处理函数 */
buttons_timer.function = buttons_timer_function;
//buttons_timer.expires = 0;
/* 3 将定时器告诉内核 */
add_timer(&buttons_timer);
2.4、在按键中断处理函数buttons_irq中
超时时间可以设置成“当前值”加上某个值。如 1 秒就是 HZ,从定义中可以看到 HZ 是 100.这里的意思是 1 秒钟里这个当前的 jiffies 值会增加 100.add_timer(&buttons_timer,jiffies+HZ);是指当前 jiffies 时间过了 100 个系统时钟中断(系统滴答)后,这个定时器的超时时间“buttons_timer”就到达了。HZ 是 1 秒,那么定时器在 10ms时启动的话,就是 HZ/100 即 10ms。假设现在,jiffies 的值为“50”,HZ 为“100”,那么这个定时器 buttons_timer 的超时时间为:
Buttons_times.expires = 50+100/100(jieeies+HZ/100) = 51.
系统是每隔 10ms 产生一个系统时钟中断,系统时钟中断中这个 jiffies 的值会累加。这里假
设 jiffies 为 50,则下一个系统时钟时,jiffies 就变成 51 了,51 一到,在这个系统时钟中断处
理函数里面会从这个定时器链表里面把这里的定时器找出来,看看哪个定时器的时间已经到
了(buttons_timer 这个定时器就在这个链表中)。若这里的 jiffies 已经大于等于这个“buttons_timer”的定时器超时时间“expires”时(jiffies>=buttons_timer.expirs),就去调用与这个定时器相关的定时器处理函数。这里要是buttons_timer.expirs 已经超时,就会调用上面自已定义的“buttons_timer_function()”这个定时器处理函数。
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
/* 修改定时器的 超时时间 = jiffies + HZ/100 = 51
* HZ相当于1s HZ/100 = 10ms
* 每隔10ms,会产生系统时钟中断,jiffies的值就会累加
* 当buttons_timer.expire = 51时
* 就会执行定时器处理函数buttons_timer_function
*/
irq_pd = (struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies + HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
2.5、在buttons_timer_function函数中
/* 判断按键状态,若没按下直接返回 */
if(!pinval)
return;
这里要判断下,因为在入口函数中没有设置超时时间,这样超时时间就为 0,一旦 add_timer()
把这个定时器放到内核中去,那么在这个系统时钟中断里面,就会 jiffies >= 0 .这样就立即
调用了定时器处理函数buttons_timer_function()。但这个时间并没按键中断产生。所以上面的“pindesc”要判断一下。
static void buttons_timer_function(unsigned long data)
{
struct pin_desc *pindesc = irq_pd;
unsigned int pinval;
/* 判断按键状态,若没按下直接返回 */
if(!pinval)
return;
/* 读取引脚值pin */
pinval = s3c2410_gpio_getpin(pindesc->pin);
/* 确定按键值 */
if(pinval)
{
/* 按下 */
key_val = 0x80 | pindesc->key_val;
}
else
{
/* 松开 */
key_val = pindesc->key_val;
}
ev_press = 1; /* 表示中断发生了 */
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
kill_fasync (&button_async, SIGIO, POLL_IN);
}
3、程序运行流程
1、应用程序运行,阻塞方式,一直等待按键按下才会返回
2、按键按下后,触发按键中断,运行按键处理函数buttons_irq并等待10ms后运行定时器处理函数buttons_timer_function。在此期间若发生抖动,则重新触发按键中断,并等待10ms后运行定时器处理函数buttons_timer_function。
3、直到最后一次出发按键中断,等待10ms后执行定时器处理函数buttons_timer_function在此函数中判断按键值并处理。