5---linux定時器消除按鍵抖動
阿新 • • 發佈:2019-01-06
概要:上一篇中我們用到了中斷來讀取按鍵電平,似乎很成功,然而當我們快速按下鬆開時,會有資料異常,是什麼導致呢?
按鍵抖動,在我們按下的時候按鍵可能會發生抖動,如圖
我們的中斷是雙邊沿觸發的,假如我們按鍵發生了抖動,那麼就觸發了五次中斷,這對我們來說實際應用上來看。是非常不穩定的,我們有兩種解決方法,一種是硬體消抖,雖然我懂一些硬體,但我不想拿自己的弱處來改進它。那麼另一種就是是軟體消抖,這一聽就在我的水平範疇內,我們可以使用定時器消抖
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()。