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);
  • 相关阅读:
    Django-中间件
    Django-cookie与session
    Django-用户认证组件
    Django-forms组件
    Django-forms校验
    Django-ajax上传文件(request数据都可以在,request.body中找到)
    Django-Ajax传递json数据
    form表单文件上传
    Django-ROM(字段,参数)
    Django-模板的继承(母版,include)
  • 原文地址:https://www.cnblogs.com/d442130165/p/5257079.html
Copyright © 2011-2022 走看看