• 用定时器实现按键消抖


       

    消除抖动的实现方法

    在发生中断后,延时一段时间(抖动时间t),再去读取按键值;

    这里实现这段延时的方法就是使用定时器;

    当按键发生中断时,启动定时器,定时器延时t秒后,再读取键值。

       

    实例

    driver.c

    1 #include <linux/module.h>
    2 #include <linux/kernel.h>
    3 #include <linux/fs.h>
    4 #include <linux/init.h>
    5 #include <linux/delay.h>
    6 #include <linux/irq.h>
    7 #include <asm/uaccess.h>
    8 #include <asm/irq.h>
    9 #include <asm/io.h>
    10 #include <asm/arch/regs-gpio.h>
    11 #include <asm/hardware.h>
    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_init ");
    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 }

       

       

    app.c

    1 #include <sys/types.h>
    2 #include <sys/stat.h>
    3 #include <fcntl.h>
    4 #include <stdio.h>
    5 #include <signal.h>
    6 #include <unistd.h>
    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%x ", keyVal);
    16
    17         return;
    18 }
    19
    20
    21 int main (void)
    22 {
    23         int oflag = 0;
    24
    25         printf("test app! ");
    26
    27         fd = open("/dev/myKey", O_RDWR);
    28         if(fd < 0)
    29         {
    30                 printf("open failed! %d ", 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

  • 相关阅读:
    一定间隔时间下重复执行一个函数的几个方法
    关于 MonoDevelop on Linux 单步调试问题的解决
    MonoDevelop 4.2.2/Mono 3.4.0 in CentOS 6.5 安装笔记
    在ASP.NET MVC 4 on Mono中使用OracleClient in CentOS 6.x的问题记录
    在CentOS 6.4 x86_32中使用Rhythmbox听MP3
    MonoDevelop 4.0.9 on CentOS 6.3 安装笔记
    MemoryMappedFile 在 Mono in Linux 的开发笔记
    Mono on CentOS 6.3 安装笔记
    庆祝下:iOS 开发者企业级计划(299美元/年帐户+邓白氏码免费) 和 Windows Phone公司应用(公司帐户99美元+Symantec企业证书299美元/年))顺利发布成功
    PowerDesigner中NAME和COMMENT的互相转换,需要执行语句
  • 原文地址:https://www.cnblogs.com/lilto/p/11878565.html
Copyright © 2020-2023  润新知