概要:上一篇中我们用到了中断来读取按键电平,似乎很成功,然而当我们快速按下松开时,会有数据异常,是什么导致呢?
按键抖动,在我们按下的时候按键可能会发生抖动,如图
在这里插入图片描述
我们的中断是双边沿触发的,假如我们按键发生了抖动,那么就触发了五次中断,这对我们来说实际应用上来看。是非常不稳定的,我们有两种解决方法,一种是硬件消抖,虽然我懂一些硬件,但我不想拿自己的弱处来改进它。那么另一种就是是软件消抖,这一听就在我的水平范畴内,我们可以使用定时器消抖
1.定时器
1.1 定义一个定时器结构体
static struct timer_list buttons_timer;
1
timer_list结构体如下:
struct timer_list {
struct list_head entry;
unsigned long expires; //超时时间,当jiffies大于它的时候会执行一次超时函数
void (*function)(unsigned long); //定时器超时函数
unsigned long data;
struct tvec_t_base_s *base;
#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
};
1.2 初始化定时器
init_timer(&buttons_timer);
1
->1.2.1) 定义超时函数
buttons_timer. function= buttons_timer_ function;
1
这个超时函数等一下我们需要编写
1.3 向内核加入一个定时器
add_timer(&buttons_timer);
1
到这一步我们定时器的初始化基本完成了,就差一个超时函数没写,写之前我们来看一下按键的中断处理函数:
static irqreturn_t buttons_irq (int irq, void *dev_id) //中断服务函数
{
irq_dev_id =(struct pin_desc *)dev_id;
mod_timer(&buttons_timer, jiffies+HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
mod_timer(&buttons_timer, jiffies+HZ/100);
当我们按键按下发生中断的时候,会进入这个中断函数,我们先不着急把电平值传出去,因为可能按键还有抖动。我们在按键中断服务函数里面启动定时器。怎么启用?
答:使用 mod_timer(&buttons_timer, jiffies+HZ/100); 这个函数会更改我们定时器的超时时间。jiffies是啥?可以理解为电脑启动到目前为止的时间,比如说我开机到现在是10秒,那么这个jiffies就是10秒。HZ是啥?一个HZ就是电脑的一秒。那么这个函数就是把超时时间就是(当前时间 + 10ms)。
假设我们按下按键,这时进入中断服务函数,把定时器超时时间变成(当前时间(假设是10s) + 10ms),
过了5ms,然后按键发生抖动了,我们又进入中断处理函数,又把定时器超时时间变成(当前时间(10s+5ms) + 10ms)
实现超时函数
static void buttons_timer_function(unsigned long data)
{
struct pin_desc * pindesc = irq_pd;
unsigned int pinval;
if (!pindesc)
return;
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); /* 唤醒休眠的进程 */
}
在超时函数里,很简单,把key值传递出来,并唤醒read()。 |