消除抖动的实现方法
在发生中断后,延时一段时间(抖动时间t),再去读取按键值;
这里实现这段延时的方法就是使用定时器;
当按键发生中断时,启动定时器,定时器延时t秒后,再读取键值。
实例
driver.c
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12
13
14 static int major;
15
16 static struct class *myKey_class;
17 static struct class_device *myKey_class_dev;
18
19 volatile unsigned long *gpfcon;
20 volatile unsigned long *gpfdat;
21
22 volatile unsigned long *gpgcon;
23 volatile unsigned long *gpgdat;
24
25 //static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
26 //static volatile int ev_press = 0;
27
28 static struct fasync_struct *button_fasyncq;
29
30 //定义原子变量,并初始化为1
31 static atomic_t canOpen = ATOMIC_INIT(1);
32
33 //定义一个定时器
34 static struct timer_list buttons_timer;
35
36 //normal:1; press:0;
37 static unsigned char keyVal = 0;
38
39 struct pin_desc {
40 unsigned int pin;
41 unsigned int key_val;
42 };
43
44 /*
45 * 按键按下键值为0x01,...; 松开键值为0x81,...
46 */
47 struct pin_desc pins_desc[3] = {
48 {S3C2410_GPF0, 0x01},
49 {S3C2410_GPF2, 0x02},
50 {S3C2410_GPG11, 0x03},
51 };
52
53 struct pin_desc *irq_pd;
54
55 static int myKey_open(struct inode *inode, struct file *file);
56 static int myKey_close(struct inode *inode, struct file *file);
57 static ssize_t myKey_read(struct file *file, char __user *buf, size_t size, loff_t *ppos);
58 static int myKey_fasync(int fd, struct file *filp, int on);
59
60
61 static struct file_operations myKey_fops = {
62 .open = myKey_open,
63 .read = myKey_read,
64 .owner = THIS_MODULE,
65 .release = myKey_close,
66 .fasync = myKey_fasync,
67 };
68
69
70 static irqreturn_t handle_buttons(int irq, void *pin_dc)
71 {
72 /* 每次发生中断,10ms后启动定时器,定时器超时,再读取键值,实现按键消抖 */
73 irq_pd = (struct pin_desc*)pin_dc;
74 mod_timer(&buttons_timer, jiffies+HZ/100); //修改定时器超时时间,启动定时器
75
76 return IRQ_RETVAL(IRQ_HANDLED);
77 }
78
79
80 static int myKey_open(struct inode *inode, struct file *file)
81 {
82 /*
83 *当原子变量为1时,驱动程序处于空闲状态,可被打开,否则打开失败并返回
84 */
85 if (!atomic_dec_and_test(&canOpen)) //atomic_dec_and_test――原子变量自减,结果为0返回ture,否则返回false
86 {
87 //atomic_inc――原子变量自加
88 atomic_inc(&canOpen); //恢复原子变量为原来值
89 return -EBUSY;
90 }
91
92 request_irq(IRQ_EINT0, handle_buttons, IRQT_BOTHEDGE, 'S2', &pins_desc[0]);
93 request_irq(IRQ_EINT2, handle_buttons, IRQT_BOTHEDGE, 'S3', &pins_desc[1]);
94 request_irq(IRQ_EINT19, handle_buttons, IRQT_BOTHEDGE, 'S5', &pins_desc[2]);
95
96 return 0;
97 }
98
99
100 static int myKey_close(struct inode *inode, struct file *file)
101 {
102 atomic_inc(&canOpen); //关闭驱动,恢复原子变量默认值
103
104 free_irq(IRQ_EINT0, &pins_desc[0]);
105 free_irq(IRQ_EINT2, &pins_desc[1]);
106 free_irq(IRQ_EINT19, &pins_desc[2]);
107
108 return 0;
109 }
110
111 int myKey_fasync(int fd, struct file *filp, int on)
112 {
113 printk('driver: fasync_initn');
114 fasync_helper(fd, filp, on, &button_fasyncq);
115
116 return 0;
117 }
118
119 static ssize_t myKey_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
120 {
121 //无中断进入休眠
122 //wait_event_interruptible(button_waitq, ev_press);
123
124 //ev_press = 0; //清除中断发生标志
125 copy_to_user(buf, &keyVal, 1);
126 return 0;
127 }
128
129
130 void handle_buttons_timer(unsigned long data)
131 {
132 unsigned int kval;
133 struct pin_desc *pinDesc = irq_pd;
134
135 //定时器初次初始化完成,超时处理,此时并未发生过按键中断
136 if (!pinDesc)
137 {
138 return;
139 }
140
141 kval = s3c2410_gpio_getpin(pinDesc->pin);
142 if (kval) //松开
143 {
144 keyVal = 0x80 | pinDesc->key_val;
145 }
146 else { //按下
147 keyVal = pinDesc->key_val;
148 }
149
150 //唤醒休眠进程
151 //ev_press = 1; //中断发生标志
152 //wake_up_interruptible(&button_waitq);
153
154 kill_fasync(&button_fasyncq, SIGIO, POLL_IN);
155 }
156
157
158 static int __init myKey_init(void)
159 {
160 /* 初始化定时器 */
161 init_timer(&buttons_timer);
162 buttons_timer.expires = 0; //设置定时器超时,默认初始化完成后进入休眠
163 buttons_timer.function = handle_buttons_timer; //注册定时器超时处理函数
164 add_timer(&buttons_timer);
165
166 /* 物理地址映射成虚拟地址 */
167 gpfcon = (volatile unsigned long*)ioremap(0x56000050, 16);
168 gpfdat = gpfcon + 1;
169
170 gpgcon = (volatile unsigned long*)ioremap(0x56000060, 16);
171 gpgdat = gpgcon + 1;
172
173 major = register_chrdev(0, 'myKey', &myKey_fops);
174
175 myKey_class = class_create(THIS_MODULE, 'myKeyclass');
176 myKey_class_dev = class_device_create(myKey_class, NULL, MKDEV(major, 0), NULL, 'myKey');
177
178 return 0;
179 }
180
181 static void __exit myKey_exit(void)
182 {
183 /* 释放虚拟地址映射 */
184 iounmap(0x56000050);
185 iounmap(0x56000060);
186
187 unregister_chrdev(major, 'myKey');
188
189 class_device_unregister(myKey_class_dev);
190 class_destroy(myKey_class);
191 return;
192 }
上一篇:S3C2440内存控制器详解
下一篇:异步通知
设计资源 培训 开发板 精华推荐
- 基于i.MX RT117H的恩智浦EdgeReady Smart HMI解决方案,具有ML视觉、语音和图形UI功能
- AD8316-EVAL,AD8316 评估板,0.1GHz 至 2.5GHz,70dB 对数检波器/控制器
- LT3970IMS-5 1.8V 降压转换器的典型应用
- LT1172CQ、1.25A 外部限流器的典型应用
- AD8354-EVALZ,AD8354 评估板,1MHz 至 2.7GHz 射频增益模块
- NCP301LSN47T1 4.7V 窗口电压检测器的典型应用
- 用于计量的 ±15V 方波放大器
- S8VK-C12024 5A/24V AC/DC电源典型应用电路
- LTC3638EMSE 高效 250mA 降压型稳压器的典型应用电路
- AND8159/D,N2压缩机使用压扩器NE570/SA571的应用电路