首先,我们要先搞明白两个问题:
1. 为什么要去抖动?
按键所用开关为机械弹性开关,当机械触点断开,闭合时,由于机械触点的弹性作用,开关不会马上稳定地接通或者断开。因而在闭合及断开的瞬间总是伴随一连串的抖动。
2. linux中为什么要用定时器去抖?
按键去抖动的方法主要有两种,一是硬件电路去抖动;另一种是软件延时去抖。而延时又一般分为两种,一种是for循环等待,另一种是定时器延时。在操作系统中,由于效率方面的原因,一般不允许使用for循环来等待,只能使用定时器。
定时器是用来流程:
1. 定义定时器变量
1 使用struct timer_list结构定义一个定时器变量,
2 struct timer_list {
3 /*
4 * All fields that change during normal runtime grouped to the
5 * same cacheline
6 */
7 struct list_head entry;
8 unsigned long expires; //设置定时器超时时间
9 struct tvec_base *base;
10
11 void (*function)(unsigned long); //定时器超时处理函数
12 unsigned long data;
13
14 int slack;
15
16 #ifdef CONFIG_TIMER_STATS
17 int start_pid;
18 void *start_site;
19 char start_comm[16];
20 #endif
21 #ifdef CONFIG_LOCKDEP
22 struct lockdep_map lockdep_map;
23 #endif
24 };
例:struct timer_list key_timer;
2. 初始化定时器
1 初始化定时器有两步:
2 1. init_timer;
3 2. 设置超时函数。
4 例:init_timer(&key_timer);
5 key_timer.function = key_timer_func;
3. add_timer注册定时器
1 例: add_timer(&key_timer);
4. mod_timer启动定时器
1 例:
2 /*jiffies为全局变量,表示当前的时间,在linux系统中1秒中有1000滴答,
3 即1秒jiffies增加1000,HZ代表一秒*/
4 mod_timer(&key_timer, jiffies + 1*HZ);
以下为带定时器去抖的按键中断驱动程序:
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 11 #define GPH2CON 0xe0200c40 12 #define GPH2DAT 0xe0200c44 13 14 struct timer_list key_timer; 15 unsigned *gpio_data; 16 17 irqreturn_t key_irq(int irq, void * dev_id) 18 { 19 //1. 检测是否发生了按键中断 20 21 22 //2. 清除已经发生的按键中断 23 24 25 //3. 打印按键值 26 27 /*启动定时器*/ 28 mod_timer(&key_timer, jiffies + HZ/50); //超时为20ms 29 30 return 0; 31 } 32 33 34 /*超时函数*/ 35 void key_timer_func(unsigned long data) 36 { 37 key_val = readl(gpio_data) & 0x01; 38 if(key_val == 0) 39 printk('key_down!n'); 40 } 41 42 43 int key_open (struct inode *inode, struct file *filp) 44 { 45 return 0; 46 } 47 48 49 void key_hw_init() 50 { 51 //unsigned int data; 52 unsigned int *gpio_config; 53 unsigned int key_val; 54 55 gpio_config = ioremap(GPH2CON, 4); 56 data = readl(gpio_config); 57 data &= ~0b1111; 58 data |= 0b1111; 59 writel(data,gpio_config); 60 61 gpio_data = ioremap(GPH2DAT, 4); 62 } 63 64 65 struct file_operations key_fops = 66 { 67 .open = key_open, 68 }; 69 70 71 struct miscdevice key_miscdevice = 72 { 73 /*MISC_DYNAMIC_MINOR代表动态分配次设备号,即由系统自动分配*/ 74 .minor = MISC_DYNAMIC_MINOR, 75 .name = 'key_miscdev', 76 .fops = &key_fops, 77 }; 78 79 80 static int key_init() 81 { 82 /*注册混杂设备*/ 83 misc_register(&key_miscdevice); 84 85 /*申请中断,如果内核中已有按键中断驱动,则需要把arch/arm/mach-s5pv210/mach-mini210.c文件的gpio_buttons定义的相关按键去掉, 86 不然板子上的按键中断就已经被占用,不能注册中断*/ 87 /*注意:中断号这个参数应该用gpio_to_irq(S5PV210_GPH2(0)),假如用了IRQ_EINT16_31则按键驱动不会工作,我个人认为是内核代码写错了*/ 88 request_irq(gpio_to_irq(S5PV210_GPH2(0)), key_irq, IRQF_TRIGGER_FALLING, 'key_miscdev', 0); 89 90 /*初始化定时器*/ 91 init_timer(&key_timer); 92 key_timer.function = key_timer_func; 93 94 /*注册定时器*/ 95 add_timer(&key_timer); 96 97 98 return 0; 99 100 } 101 102 103 static void key_exit() 104 { 105 /*注销设备*/ 106 misc_deregister(&key_miscdevice); 107 } 108 109 110 MODULE_LICENSE('GPL'); 111 112 module_init(key_init); 113 module_exit(key_exit);
上一篇:ARM裸编程系列---UART
下一篇:TQ210搭载Android4.0.3系统构建之LED从驱动到HAL到JNI到应用程序(驱动篇)
推荐阅读最新更新时间:2026-03-19 11:22
- 基于 Blackfin 数字信号处理器 (DSP) 的 ADZS-BF518F-EZLITE、ADSP-BF518F EZ-Kit Lite 评估系统
- 使用 ON Semiconductor 的 CAT3200Z 的参考设计
- LTC2162 演示板,16 位 65Msps ADC,LVDS 输出,5-140MHz
- 使用 Analog Devices 的 LTC3526BEDC-2 的参考设计
- LT3091HT7 在极低输出电压下低压降操作的典型应用
- 蓝牙协议分析工具nRF52840 MDK USB Dongle
- NCV2902DR2G 维恩桥振荡器运算放大器的典型应用
- LTC4100EGN 演示板,智能电池充电器 DCIN = 15V-20V / 3.5V
- TC78H620FNG 双桥直流有刷电机驱动器评估板
- 带有 DRP w/Try.SRC 和 Type-C 插座的 PTN5110 USB PD 的典型应用

采用51单片机定时器方式的无抖动的4x4矩阵按键程序
Follow_me第三季第一期代码
可编程控制器应用基础
现代雷达系统的信号设计
BFR340T






京公网安备 11010802033920号