Using timer to debounce buttons

Publisher:CreativeDreamerLatest update time:2024-07-31 Source: cnblogsKeywords:Timer Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

How to eliminate jitter

After an interrupt occurs, delay for a period of time (jitter time t) before reading the key value;

The method to achieve this delay here is to use a timer;

When a key interrupt occurs, the timer is started, and the key value is read after the timer delays for t seconds.

Examples

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 //Define atomic variables and initialize them 1
31 static atomic_t canOpen = ATOMIC_INIT(1);
32
33 //Define a timer
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 * The key value when the key is pressed is 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 /* Every time an interrupt occurs, the timer is started after 10ms. When the timer times out, the key value is read to achieve key debounce*/
73 irq_pd = (struct pin_desc*)pin_dc;
74 mod_timer(&buttons_timer, jiffies+HZ/100); //Modify the timer timeout and start the timer
75
76 return IRQ_RETVAL(IRQ_HANDLED);
77 }
78
79
80 static int myKey_open(struct inode *inode, struct file *file)
81 {
82 /*
83 *When the atomic variable is 1, the driver is in idle state and can be opened, otherwise the opening fails and returns
84 */
85 if (!atomic_dec_and_test(&canOpen)) //atomic_dec_and_test--Atomic variable self-decrement, the result is 0 and returns true, otherwise returns false
86 {
87 //atomic_inc--Atomic variable self-increment
88 atomic_inc(&canOpen); //Restore the atomic variable to the original value
89 return -EBUSY;
90
103
104 free_irq(IRQ_EINT0, &pins_desc[0]); 105 } 96 97 108 static int myKey_close(struct inode *inode, struct file *file) 109 { 110 atomic_inc(&canOpen); //Close the driver and restore the default value of atomic variables 111 112
free_irq(IRQ_EINT0, &pins_desc[0]); 113 114 free_irq(IRQ_EINT19, handle_buttons,
IRQT_BOTHEDGE, "S5", &pins_desc[2]); 115 } 96 97 118 static int myKey_close(struct inode *inode, struct file *file) 119 { 120 atomic_inc(&canOpen); //Close the driver and restore the default value of atomic variables 121 122 free_irq(IRQ_EINT2, &pins_desc[1]); 123 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 //Enter sleep without interruption 122 //wait_event_interruptible(button_waitq, ev_press); 123 124 //ev_press = 0; //Clear interrupt flag 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 //Timer initialization completed, timeout processing, no key interrupt occurred at this time









































136 if (!pinDesc)
137 {
138 return;
139 }
140
141 kval = s3c2410_gpio_getpin(pinDesc->pin);
142 if (kval) //Release
143 {
144 keyVal = 0x80 | pinDesc->key_val;
145 }
146 else { //Press
147 keyVal = pinDesc->key_val;
148 }
149
150 //Wake up the sleeping process
151 //ev_press = 1; //Interrupt flag
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 /* Initialize timer*/
161 init_timer(&buttons_timer);
162 buttons_timer.expires = 0; //Set timer timeout, default enters sleep after initialization is completed
163 buttons_timer.function = handle_buttons_timer; //Register timer timeout processing function
164 add_timer(&buttons_timer);
165
166 /* Map physical address to virtual address*/
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 /* Release virtual address mapping*/
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 }

app.c

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7
8 int fd;
9
10 void handle_signal(int signum)
11 {
12 unsigned char keyVal;
13
14 read(fd, &keyVal, 1);
15 printf("keyVal: 0x%xn", keyVal);
16
17 return ;
18 }
19
20
21 int main (void)
22 {
23 int oflag = 0;
24
25 printf("test app!n");
26
27 fd = open("/dev/myKey", O_RDWR);
28 if( fd < 0)
29 {
30 printf("open failed! %dn", fd);
31 return -1;
32 }
33
34 signal(SIGIO, handle_signal);
35
36 fcntl(fd, F_SETOWN, getpid());
37 oflag = fcntl(fd, F_GETFL);
38 fcntl(fd, F_SETFL, oflag | O_ASYNC);
39
40 while(1)
41 {
42 sleep(5);
43 }
44 return 0;
45 }

Makefile

1 KERN_DIR = /work/system/linux-2.6.22.6
2
3 all:
4 make -C $(KERN_DIR) M=`pwd` modules
5
6 clean:
7 make -C $(KERN_DIR) M=`pwd` modules clean
8 rm -rf modules.order
9
10 obj-m += myKey_all.o


Keywords:Timer Reference address:Using timer to debounce buttons

Previous article:Detailed Explanation of S3C2440 Memory Controller
Next article:Asynchronous Notification

Recommended ReadingLatest update time:2024-11-15 07:50

How should beginners learn with development boards such as 2440 and 6410?
        (Because I found that many comrades are confused, I think this post is more valuable, and my understanding of these will continue to update and improve, so I will keep updating and improving this post, and I also hope that more people will come to discuss and analyze, and even put forward opinions against criti
[Microcontroller]
3. Setting the clock and timer of the bare metal system of s3c2440
3. System clock and timer settings ⑴Analysis of system clock principle The clock determines the execution speed of 2440. 2440 can use an external clock source, or use an external crystal oscillator and then obtain the clock frequency through the internal crystal oscillator. See the figure below for specific select
[Microcontroller]
3. Setting the clock and timer of the bare metal system of s3c2440
2440 Bare Metal Programming - Three General I/O Ports
The S3C2440A has 130 multi-function input/output pins, which are included in the following 9 groups of ports. ● 1 25-bit output port (Port A). ● 1 11-bit output port (Port B). ● 4 16-bit input/output ports (Ports C, D, E, G). ● 1 8-bit input/output port (Port F). ● 1 9-bit input/output port (Port H). ● 1 13-bit input/
[Microcontroller]
2440 Bare Metal Programming - Three General I/O Ports
S3C2440 learning path - simple configuration of 007UART
1. Basic knowledge The serial port is one of the most basic functions of various chips. After the serial port is configured, the program can print various information through the serial port, which is convenient for code debugging. The main parameters of the serial port are 4: baud rate, data width, check bit, stop bi
[Microcontroller]
S3C2440 learning path - simple configuration of 007UART
The use of PWM and timer of S3C2440
  There are 5 16-bit timers in the s3c2440 chip, 4 of which (timer 0 to timer 3) have pulse width modulation function, that is, they all have an output pin, and the timer can be used to control the periodic high and low level changes of the pin. Timer 4 has no output pin. This was used in the last offline PWM test pro
[Microcontroller]
Development environment of keil4 for s3c2440 bare metal under win7
ADS is unstable under Windows 7 and has not been officially updated for a long time. I often use MDK for embedded software development. MDK is simple, easy to use and powerful, so I want to use MDK to develop bare metal S3C2440. I found many blogs of great people on the Internet. When setting up the environment, many
[Microcontroller]
Development environment of keil4 for s3c2440 bare metal under win7
Lessons learned from TQ2440 LCD test failure
Test environment: TQ2440 development board (matched with TQ4.3-inch screen) Test bibliography: "Practical Bare Metal Development of ARM Processors - Mechanisms rather than Strategies" (hereinafter referred to as "Practical Bare Metal Development") In Chapter 13 of "Bare Metal Development Practice", the LCD controller
[Microcontroller]
Lessons learned from TQ2440 LCD test failure
S3C2440 development board bare metal program series 05 - timer PWM
1. PWM Overview Timers 0, 1, 2, and 3 have PWM functions. TCNTBn is the initial count value. After the timer is turned on, it counts down by 1. The value of TCMPBn is used for comparison. The initial value is 0, so when TCNTBn counts down by 1 to 0, it is equal to TCMPBn, and TOUTn will flip. Therefore, the value
[Microcontroller]
S3C2440 development board bare metal program series 05 - timer PWM
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号