/* AUTHOR: Pinus
* Creat on : 2018-10-25
* KERNEL : linux-4.4.145
* BOARD : JZ2440(arm9 s3c2440)
* REFS : 韦东山视频教程第二期
通过定时器完成防抖动的总结
*/
除颤吗。。。能看的应该都懂为什么,单片机上不也是常用什么delay()或者也是定时器进行除颤吗,避免误触呗。
当按键发生时产生中断,在中断服务程序中修改一个定时器的定时时间为10ms,并从10ms开始重新计数。定时器时间到后产生定时器中断,按键处理放在定时器中断里面。这样当10ms内有多个中断发生时只有最后一个中断起作用,以达到消除抖动的目的。
上张韦老师的图片吧
目的:给前面的按键程序加上定时器防止按键抖动引起的误差
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
好像只追求实现了,没讲什么原理,因为我现在也不懂原理,只会用,留个思考以后填坑吧【思考?】