5---linux定时器消除按键抖动

概要:上一篇中我们用到了中断来读取按键电平,似乎很成功,然而当我们快速按下松开时,会有数据异常,是什么导致呢?

按键抖动,在我们按下的时候按键可能会发生抖动,如图

5---linux定时器消除按键抖动_第1张图片
我们的中断是双边沿触发的,假如我们按键发生了抖动,那么就触发了五次中断,这对我们来说实际应用上来看。是非常不稳定的,我们有两种解决方法,一种是硬件消抖,虽然我懂一些硬件,但我不想拿自己的弱处来改进它。那么另一种就是是软件消抖,这一听就在我的水平范畴内,我们可以使用定时器消抖

1.定时器

1.1 定义一个定时器结构体

static struct timer_list buttons_timer;

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.2.1) 定义超时函数

buttons_timer. function= buttons_timer_ function;

这个超时函数等一下我们需要编写

1.3 向内核加入一个定时器

add_timer(&buttons_timer);  
到这一步我们定时器的初始化基本完成了,就差一个超时函数没写,写之前我们来看一下按键的中断处理函数:
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()。

这样我们就实现了软件消抖

你可能感兴趣的:(5---linux定时器消除按键抖动)