(3.5)一个按键所能涉及的:定时器防抖动

/* AUTHOR: Pinus

* Creat on : 2018-10-25

* KERNEL : linux-4.4.145

* BOARD : JZ2440(arm9 s3c2440)

* REFS : 韦东山视频教程第二期

               通过定时器完成防抖动的总结

*/

概述

        除颤吗。。。能看的应该都懂为什么,单片机上不也是常用什么delay()或者也是定时器进行除颤吗,避免误触呗。

当按键发生时产生中断,在中断服务程序中修改一个定时器的定时时间为10ms,并从10ms开始重新计数。定时器时间到后产生定时器中断,按键处理放在定时器中断里面。这样当10ms内有多个中断发生时只有最后一个中断起作用,以达到消除抖动的目的。

上张韦老师的图片吧

(3.5)一个按键所能涉及的:定时器防抖动_第1张图片

实验

目的:给前面的按键程序加上定时器防止按键抖动引起的误差

1、定义一个定时器结构体

static struct timer_list button_timer;

2、在init函数中初始化这个定时器
 

static int __init buttons_drv_init(void)
{
    init_timer(&button_timer); // 初始化这个定时器
    setup_timer(&button_timer, button_expire_timeout, 0); //button_timer.expires = 0; 
    add_timer(&button_timer); // 将这个定时器告诉内核,可以开始了
    /**
    * add_timer - start a timer
    * @timer: the timer to be added
    *
    * The kernel will do a ->function(->data) callback from the
    * timer interrupt at the ->expires point in the future. The
    * current time is 'jiffies'.
    *
    * The timer's ->expires, ->function (and if the handler uses it, ->data)
    * fields must be set prior calling this function.
    *
    * Timers with an ->expires field in the past will be executed in the next
    * timer tick.
    */

    major = register_chrdev(0, "buttons_dev", &jz2440_buttons_fops); //注册 告诉内核
    ...
    return 0;
}

主要是设置定时器超时的处理函数

#define setup_timer(timer, fn, data) \
    __setup_timer((timer), (fn), (data), 0)


#define __setup_timer(_timer, _fn, _data, _flags) \
    do { \
    __init_timer((_timer), (_flags)); \
    (_timer)->function = (_fn); \
    (_timer)->data = (_data); \
    } while (0)

3、定义定时器超时处理函数:

这个函数的功能在本例子中就是都取按键键值,并发送信号,可将上一篇博文中的中断处理函数中的内容直接交给这个函数,即:

/* Handle the timer event */
static void button_expire_timeout(unsigned long unused)
{
    struct intpin_desc * pindesc = irq_pd;
    unsigned int pinval;


    if (!pindesc)
        return 0;

    pinval = gpio_get_value(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);
}

注意:

设备描述符是从中断服务程序中获得,即irq_pd要从中断服务程序中获得(可定义一个全局变量)

if(!pindesc) //防止初始化时add_timer后立即执行定时器中断

    return;

防止在init函数中进行addtimer后,系统会马上执行定时器服务程序,这与我们想要的是不符的

 

4、修改按键中断服务程序

按键中断服务程序主要负责将到来的中断推迟10ms执行要进行的动作。

static irqreturn_t buttons_irq(int irq,void *dev_id)
{
    irq_pd = (struct pin_desc *)dev_id;
    /*10ms后启动定时器*/
    mod_timer(&button_timer, jiffies+HZ/100);

    return IRQ_HANDLED;
}

irq_pd = (struct pin_desc *)dev_id; 即获得设备描述符

mod_timer 修改定时器目的值,这个值是以jiffies为基准,即现在时刻的值是jiffies,程序要在10ms后进行处理,所以 +HZ/200  1HZ=1s  

好像只追求实现了,没讲什么原理,因为我现在也不懂原理,只会用,留个思考以后填坑吧【思考?】

 

 

 

 

你可能感兴趣的:(cdev总结2018)