在前面的两篇文章《 Linux内核驱动中断处理机制之外部中断
》和《 Linux内核驱动中断处理机制之软中断和定时器
》中,分别描述了在Linux内核驱动中,外部中断的使用、软中断和定时器。
因为在这之前所实现的按键驱动并没有实现消抖操作,所以经常性的只按下了一次按键,但是却产生了几个按键信息(抖动导致的)。效果如下:
本文将通过Linux内核定时器解决按键的消抖问题。
一、理论基础
1、机械按键的结构
如上图所示,当按键被按下时,按键中连接两个引脚的金属片相互接触导通,使得按键的两个引脚导通,从而表示按键按下。
2、机械按键按下和抬起的过程
如上图所示A区域,按键按下的过程中,不可避免的会使得按键内部的金属片进行短暂的接触,然后又断开,这使得CPU会将按键误识别为按键已经按下了,但是实际上按键并未按下,从而产生误识别。而我们用户需要的是在B区域时,按键完全的按下了。这就是抖动造成的误识别。
那么解决抖动的方案是 :
“当第一次检测到按键按下时,将其状态记录下来,等待一段时间后(注意:这里的等待并不一定或者说并不是延时,而是CPU可以先去处理别的事件;
这段时间通常是毫秒级别的,通常10ms~40ms),再回来再次检测按键状态,如果此时按键还是按下的状态,则说明按键确实按下了;否则说明按键并没有按下”。
二、程序的实现
1、程序实现思路
(1)使用函数接口init_timer和add_timer初始化和注册一个内核定时器。
如上图,Key_Dithering_timer为定时器处理函数。
(2)在按键中断的下半部处理函数修改并启用定时器
思路是:当按键按下之后,会产生按键中断,进入中断下半部之后,启用一个定时器,并且定时从当前时间开始之后的20ms。此时CPU可以去处理其他事件任务,当内核定时器时间到达之后,定时器处理函数Key_Dithering_timer将得到执行。
如上图所示Demo即为中断下半部程序。使用mod_timer函数接口来修改定时器的expire。其中buttons_timer为装载驱动是注册的内核定时器,jiffies表示设备从开机到当前时间的定时器中断次数计数;
HZ用来定义1s有多少次定时器中断(timer
interrupt),在笔者当前使用的Linux内核中HZ的值被定义为200。所以定时20ms的定时器中断计数为HZ/50(关于jiffies和HZ的详细说明,在后续文章中)。
(3)在定时器处理函数Key_Dithering_timer中实现键值的判断
如上图定时器处理函数中,判断是哪一个按键被按下,如果需要详细处理,那么可以在其中添加各个按键代表的键值。在这里主要是验证驱动程序,并不实现应用程序功能。
2、驱动程序的装载
3、驱动程序的卸载
卸载驱动是,需要使用接口del_timer将申请注册的定时器从内核中删除。
四、程序运行效果
编译内核得到驱动文件buttons_timer_driver.ko,将其拷贝到板卡根文件系统,通过命令:insmod
buttons_timer_driver.ko将驱动装载到Linux内核中。按下按键后,从内核中将按键按下的状态打印出来。如下图:
更多Linux教程请查看菜单