zoukankan      html  css  js  c++  java
  • [国嵌攻略][122][按键定制器去抖]

    按键抖动

    按键所用的开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,开关不会马上稳定地接通或断开。因而在闭合及断开的瞬间总伴随有一连串的抖动。

    按键去抖动的方法主要有两种,一种是硬件电路去抖;另一种就是软件延时去抖。而延时去抖一般又分为两种,一种是for循环等待,另一种是定时器延时。在操作系统中,由于效率方面的原因,一般不允许使用for循环来等待,只能使用定时器。

    内核定时器

    Linux内核使用struct timer_list来描述一个定时器:

    struct timer_list{

        struct list_head entry;

        unsigned long expires;   //定时时间

        void (*function)(unsigned long);   //处理函数

        unsigned long data;

        struct tvec_base *base;

    };

    定时器使用流程

    1.定义定时器

    2.初始化定时器

    2.1.init_timer初始化

    2.2.设置超时函数

    3.add_timer注册定时器

    4.启动定时器器

    4.1.设置超时时间

    4.2.mod_timer启动定时器

    jiffies表示系统当前的时间,单位是嘀嗒数,一秒钟有1000个嘀嗒。HZ表示一秒。

    keydev.c

    /********************************************************************
    *头文件
    *********************************************************************/
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/miscdevice.h>
    #include <linux/interrupt.h>
    #include <linux/io.h>
    #include <linux/fs.h>
    
    /********************************************************************
    *宏定义
    *********************************************************************/
    #define GPGCON 0x56000060   //按键控制寄存器地址
    #define GPGDAT 0x56000064   //按键数据寄存器地址
    
    /********************************************************************
    *全局变量
    *********************************************************************/
    unsigned int *keycon;       //按键控制指针
    unsigned int *keydat;       //按键数据指针
    
    struct work_struct *work;   //按键工作
    struct timer_list timer;    //按键定时
    
    /********************************************************************
    *定时处理
    *********************************************************************/
    //设备定时
    void key_timer(unsigned long data){
        //读取按键状态
        unsigned short keyTmp;
        int level;
        
        keyTmp = readw(keydat);    //获取GPGDAT值
        level = keyTmp & 0x0001;   //获取按键电平
        
        //判断按键状态
        if(level == 0){
            printk("key down!
    ");
        }
    }
    
    /********************************************************************
    *中断处理
    *********************************************************************/
    //设备中断下部
    void key_work(struct work_struct *work){
        //启动定时设备
        mod_timer(&timer, jiffies + HZ/100);   //jiffies表示系统当前嘀嗒数,1HZ = 1s = 1000jiffies
    }
    
    //设备中断上部
    irqreturn_t key_irq(int irq, void *dev_id){
        //处理硬件相关
        
        //提交硬件无关
        schedule_work(work);
        
        return 0;
    }
    
    /********************************************************************
    *设备方法
    *********************************************************************/
    //设备打开
    int key_open(struct inode *node, struct file *filp){
        return 0;
    }
    
    //设备关闭
    int key_close(struct inode *node, struct file *filp){
        return 0;
    }
    
    //设备方法
    struct file_operations key_fops = {
        .open      = key_open,
        .release   = key_close
    };
    
    /********************************************************************
    *模块安装
    *********************************************************************/
    //混杂设备
    struct miscdevice misdev = {
        .minor = 200,        //次设备号
        .name  = "keydev",   //设备名称
        .fops  = &key_fops   //设备方法
    };
    
    //注册硬件
    void handware_init(void){
        //初始化按键控制寄存器
        unsigned int keyTmp;
        
        keycon = ioremap(GPGCON, 4);   //虚拟地址映射
        
        keyTmp = readl(keycon);   //获取GPGCON值
        keyTmp &= ~(0x3<<0);      //GPG0[1:0]:00
        keyTmp |=  (0x2<<0);      //GPG0[1:0]:EINT[8]
        writel(keyTmp, keycon);   //设置GPGCON值
        
        //初始化按键状态寄存器
        keydat = ioremap(GPGDAT, 2);   //虚拟地址映射
    }
    
    //安装模块
    static int key_init(void){
        //注册混杂设备
        misc_register(&misdev);
        
        //注册硬件设备
        handware_init();
            
        //注册中断处理
        request_irq(IRQ_EINT8, key_irq, IRQF_TRIGGER_FALLING, "keyirq", 0);   //下降沿触发,IRQ_EINT8定义在irqs.h文件中
        
        //注册工作队列
        work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
        INIT_WORK(work, key_work);
        
        //注册定时设备
        init_timer(&timer);           //初始化定时器
        timer.function = key_timer;   //添加定时函数
        add_timer(&timer);            //添加定时设备
        
        return 0;
    }
    
    //卸载模块
    static void key_exit(void){
        //注销混杂设备
        misc_deregister(&misdev);
        
        //注销中断处理
        free_irq(IRQ_EINT8, 0);
    }
    
    /********************************************************************
    *模块声明
    *********************************************************************/
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("D");
    MODULE_DESCRIPTION("");
    MODULE_VERSION("v1.0");
    
    module_init(key_init);
    module_exit(key_exit);
  • 相关阅读:
    ERROR Function not available to this responsibility.Change responsibilities or contact your System Administrator.
    After Upgrade To Release 12.1.3 Users Receive "Function Not Available To This Responsibility" Error While Selecting Sub Menus Under Diagnostics (Doc ID 1200743.1)
    产品设计中先熟练使用铅笔 不要依赖Axure
    12.1.2: How to Modify and Enable The Configurable Home Page Delivered Via 12.1.2 (Doc ID 1061482.1)
    Reverting back to the R12.1.1 and R12.1.3 Homepage Layout
    常见Linux版本
    网口扫盲二:Mac与Phy组成原理的简单分析
    VMware 8安装苹果操作系统Mac OS X 10.7 Lion正式版
    VMware8安装MacOS 10.8
    回顾苹果操作系统Mac OS的发展历史
  • 原文地址:https://www.cnblogs.com/d442130165/p/5257079.html
Copyright © 2011-2022 走看看