娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

Linux驅動之定時器在按鍵去抖中的應用

發布者:心靈舞動最新更新時間:2024-08-20 來源: elecfans關鍵字:Linux驅動  定時器  按鍵去抖 手機看文章 掃描二維碼
隨時隨地手機看文章

機械按鍵在按下的過程中會出現抖動的情況,如下圖,這樣就會導致本來按下一次按鍵的過程會出現多次中斷,導致判斷出錯。在按鍵驅動程序中我們可以這么做:

在按鍵驅動程序中我們可以這么做來取消按鍵抖動的影響:當出現一個按鍵中斷后不會馬上去處理它,而是延時一個抖動時間(一般10ms),如果在這個時間內再次出現中斷那么再次延時10ms。這樣循環,一直到在這個10ms內只有一個按鍵中斷,那么就認為這次是真的按鍵值,然后在定時器處理函數里處理它。上述過程可以利用內核的定時器來實現。

定時器二要素:定時時間、定時時間到后做什么事情。根據這兩個要素來編寫程序,直接在sixth_drv.c的驅動程序上更改直接看到代碼

1、定時器的創建,先建立一個定時器結構

static struct timer_list buttons_timer;//定義一個定時器

2、在模塊裝載時初始化定時器


static int sixth_drv_init(void)

{

    /*增加一個定時器用于處理按鍵抖動*/

    init_timer(&buttons_timer);

    buttons_timer.expires = 0;//定時器的定時時間

//    buttons_timer->data = (unsigned long) cs;

    buttons_timer.function = buttons_timeout;//定時時間到后的處理函數

    add_timer(&buttons_timer);//將定義的定時器放入定時器鏈表

    

    sixthmajor = register_chrdev(0, 'buttons', &sixth_drv_ops);//注冊驅動程序


    if(sixthmajor < 0)

        printk('failes 1 buttons_drv registern');

    

    sixth_drv_class = class_create(THIS_MODULE, 'buttons');//創建類

    if(sixth_drv_class < 0)

        printk('failes 2 buttons_drv registern');

    sixth_drv_class_dev = class_device_create(sixth_drv_class, NULL, MKDEV(sixthmajor,0), NULL,'buttons');//創建設備節點

    if(sixth_drv_class_dev < 0)

        printk('failes 3 buttons_drv registern');


    

    gpfcon = ioremap(0x56000050, 16);//重映射

    gpfdat = gpfcon + 1;

    gpgcon = ioremap(0x56000060, 16);//重映射

    gpgdat = gpgcon + 1;


    printk('register buttons_drvn');

    return 0;

}


3、編寫定時器處理函數


static void buttons_timeout(unsigned long data)

{

    unsigned int pin_val;

    static long cnt=0;

    

    //printk('timeout cnt : %dn',++cnt);

    if(pin_des==NULL)

        return;

    else

    {

    //    printk('pin_des != NULLn');

        

        pin_val = s3c2410_gpio_getpin(pin_des->pin);

        

        if(pin_val) //按鍵松開

            key_val = 0x80 | pin_des->key_val;

        else

            key_val = pin_des->key_val;



        wake_up_interruptible(&button_waitq);   /* 喚醒休眠的進程 */

        ev_press = 1;    

        

        kill_fasync(&sixth_fasync, SIGIO, POLL_IN);//發生信號給進程

    }

}


4、當在卸載驅動時將定時器刪除;在中斷處理程序中直接改變定時器的超時時間,并記錄下是哪個按鍵按下的即可,其他處理都在定時器超時函數中。直接看到完整代碼:


#include <linux/module.h>

#include

#include

#include

#include         //含有iomap函數iounmap函數

#include //含有copy_from_user函數

#include //含有類相關的處理函數

#include //含有S3C2410_GPF0等相關的

#include     //含有IRQ_HANDLEDIRQ_TYPE_EDGE_RISING

#include    //含有IRQT_BOTHEDGE觸發類型

#include //含有request_irq、free_irq函數

#include

#include   //含有各種錯誤返回值

//#include




static struct class *sixth_drv_class;//類

static struct class_device *sixth_drv_class_dev;//類下面的設備

static int sixthmajor;


static unsigned long *gpfcon = NULL;

static unsigned long *gpfdat = NULL;

static unsigned long *gpgcon = NULL;

static unsigned long *gpgdat = NULL;


struct fasync_struct *sixth_fasync;

    

static unsigned int key_val;


struct pin_desc 

{

    unsigned int pin;

    unsigned int key_val;

};


static struct pin_desc  pins_desc[4] = 

{

    {S3C2410_GPF0,0x01},

    {S3C2410_GPF2,0x02},

    {S3C2410_GPG3,0x03},

    {S3C2410_GPG11,0x04}

};


static struct pin_desc *pin_des=NULL;


static unsigned int ev_press;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);//注冊一個等待隊列button_waitq


 static atomic_t open_flag = ATOMIC_INIT(1);     //定義原子變量open_flag 并初始化為1


static DECLARE_MUTEX(button_lock);     //定義互斥鎖


static struct timer_list buttons_timer;//定義一個定時器

/*

  *0x01、0x02、0x03、0x04表示按鍵被按下

  */

  

/*

  *0x81、0x82、0x83、0x84表示按鍵被松開

  */


/*

  *利用dev_id的值為pins_desc來判斷是哪一個按鍵被按下或松開

  */

static irqreturn_t buttons_irq(int irq, void *dev_id)

{

    pin_des = (struct pin_desc *)dev_id;//取得哪個按鍵被按下的狀態

    mod_timer(&buttons_timer, jiffies+HZ/100);//10ms之后調用定時器處理函數

    

    return IRQ_HANDLED;

}




static int sixth_drv_open (struct inode * inode, struct file * file)

{

    int ret;



//    if(atomic_dec_and_test(&open_flag)==0)//自檢后是否為0,不為0說明已經被人調用

//    {

//        atomic_inc(&open_flag);//原子變量+1

//        return -EBUSY;

//    }

    if(file->f_flags & O_NONBLOCK)//非阻塞方式

    {

        if(down_trylock(&button_lock))//獲取信號量失敗則返回

            return -EBUSY;

    }

    else    

        down(&button_lock);//獲得信號量

    

    ret = request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, 's1', (void * )&pins_desc[0]);

    if(ret)

    {

        printk('open failed 1n');

        return -1;

    }

    ret = request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, 's2', (void * )& pins_desc[1]);

    if(ret)

    {

        printk('open failed 2n');

        return -1;

    }

    ret = request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, 's3', (void * )&pins_desc[2]);

    if(ret)

    {

        printk('open failed 3n');

        return -1;

    }

    ret = request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, 's4', (void * )&pins_desc[3]);

    if(ret)

    {

        printk('open failed 4n');

        return -1;

    }

    

    return 0;

}



static int sixth_drv_close(struct inode * inode, struct file * file)

{

//    atomic_inc(&open_flag);//原子變量+1

    up(&button_lock);//釋放信號量

    

    free_irq(IRQ_EINT0 ,(void * )&pins_desc[0]);


     free_irq(IRQ_EINT2 ,(void * )& pins_desc[1]);


    free_irq(IRQ_EINT11 ,(void * )&pins_desc[2]);


    free_irq(IRQ_EINT19 ,(void * )&pins_desc[3]);


    return 0;

}


static ssize_t sixth_drv_read(struct file * file, char __user * userbuf, size_t count, loff_t * off)

{

    int ret;


    if(count != 1)

    {

        printk('read errorn');

        return -1;

    }


    if(file->f_flags & O_NONBLOCK)//非阻塞方式

    {

        if(!ev_press)//判斷是否有按鍵按下,如果沒有直接返回

        {

                key_val = 0;

                ret = copy_to_user(userbuf, &key_val, 1);

                return -EBUSY;

        }

    }

    else//如果沒有按鍵動作,直接進入休眠

        wait_event_interruptible(button_waitq, ev_press);//將當前進程放入等待隊列button_waitq中

    

    ret = copy_to_user(userbuf, &key_val, 1);

    ev_press = 0;//按鍵已經處理可以繼續睡眠

    

    if(ret)

    {

        printk('copy errorn');

        return -1;

    }

    

    return 1;

}


static unsigned int sixth_drv_poll(struct file *file, poll_table *wait)

{

    unsigned int ret = 0;

    poll_wait(file, &button_waitq, wait);//將當前進程放到button_waitq列表


    if(ev_press)

        ret |=POLLIN;//說明有數據被取到了


    return ret;

}




static int sixth_drv_fasync(int fd, struct file * file, int on)

{

    int err;

    printk('fansync_helpern');

    err = fasync_helper(fd, file, on, &sixth_fasync);//初始化sixth_fasync

    if (err < 0)

        return err;

    return 0;

}



static struct file_operations sixth_drv_ops = 

{

    .owner   = THIS_MODULE,

    .open    =  sixth_drv_open,

    .read     = sixth_drv_read,

    .release = sixth_drv_close,

    .poll      =  sixth_drv_poll,

    .fasync   = sixth_drv_fasync,

    

};


static void buttons_timeout(unsigned long data)

{

    unsigned int pin_val;

    static long cnt=0;

    

    //printk('timeout cnt : %dn',++cnt);

    if(pin_des==NULL)

        return;

    else

    {

    //    printk('pin_des != NULLn');

        

        pin_val = s3c2410_gpio_getpin(pin_des->pin);

        

        if(pin_val) //按鍵松開

            key_val = 0x80 | pin_des->key_val;

        else

            key_val = pin_des->key_val;



        wake_up_interruptible(&button_waitq);   /* 喚醒休眠的進程 */

        ev_press = 1;    

        

        kill_fasync(&sixth_fasync, SIGIO, POLL_IN);//發生信號給進程

[1] [2]
關鍵字:Linux驅動  定時器  按鍵去抖 引用地址:Linux驅動之定時器在按鍵去抖中的應用

上一篇:Linux驅動之輸入子系統簡析
下一篇:Linux驅動之同步、互斥、阻塞的應用

推薦閱讀最新更新時間:2025-06-07 23:41

Linux下GPIO驅動(三) ----gpio_desc()的分析
上篇最后提出的疑問是結構體gpio_chip中的成員函數set等是怎么實現的,在回答之前先介紹下gpio_desc這個結構體。 如上圖所示,右上方部分為GPIO驅動對其它驅動提供的GPIO操作接口,其對應的右下方部分為GPIO硬件操作接口,也就是說對外提供的接口最終會一一對應的對硬件GPIO進行操作。 再來看左邊部分,左上方部分為一全局數組,記錄各個GPIO的描述符,即對應左下方的gpio_desc結構體,其中gpio_chip指向硬件層的GPIO,flags為一標志位,用來指示當前GPIO是否已經占用,當用gpio_request申請GPIO資源時,flags位就會置位,當調用gpio_free釋放GPIO
[單片機]
<font color='red'>Linux</font>下GPIO<font color='red'>驅動</font>(三) ----gpio_desc()的分析
Linux驅動之LED驅動編寫
1、查看原理圖,確定需要控制的IO端口 打開原理圖,確定需要控制的IO端口為GPF4、GPF5、GPF6。 2、查看芯片手冊,確定IO端口的寄存器地址,可以看到它的基地址為0x56000050 3、編寫驅動代碼,編寫驅動代碼的步驟如下: 1)、編寫出口、入口函數。   a、首先利用register_chrdev函數如果第一個參數為0的話那么會自動分配一個主設備號為Firstmajor ;第二個參數firstled_drv會是這個字符設備的名稱可以利用命令cat /proc/devices看到;第三個參數是它的first_drv_fops結構體,這個結構體是字符設備中最主要的,后面再說明。   b、接著利用clas
[單片機]
<font color='red'>Linux</font><font color='red'>驅動</font>之LED<font color='red'>驅動</font>編寫
Linux驅動之異步通知的應用
前面的按鍵驅動方式都是應用程序通過主動查詢的方式獲得按鍵值的: 1、查詢方式 2、中斷方式 3、poll機制 下面介紹第四種按鍵驅動的方式 4、異步通知:它可以做到應用程序不用隨時去查詢按鍵的狀態,而等待有按鍵被按下后,驅動程序主動發消息給應用程序,應用程序再去處理。 比如說:kill -9 pid即是一種發信號的過程:其中9就是信號值,pid就是被發送的進程的進程號 a、一個簡單的異步通知的例子 b、編寫測試程序實現異步通知 c、更改按鍵驅動實現異步通知 1、一個簡單的異步通知的例子 直接看到程序源碼,可以看到這個程序在主程序里面什么事情也沒有做,一直處于睡眠狀態。 #includ
[單片機]
Linux下S3C2440 RTC實時時鐘驅動配置與修改
Linux下對S3C2440 RTC的支持非常完善,我們只需要做簡單的修改,即可使用RTC 1、vi arch/arm/mach-s3c2440/mach-smdk2440.c static struct platform_device *smdk2440_devices __initdata = { &s3c_device_usb, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c0, &s3c_device_iis, &s3c_device_rtc, //這里我們添加上RTC平臺設備,默認是沒添加的 }; 2、make zImage 3、使用與測試 L
[單片機]
linux設備樹-按鍵中斷驅動
---------------------------------------------------------------------------------------------------------------------------- 內核版本:linux 5.2.8 根文件系統:busybox 1.25.0 u-boot:2016.05 ---------------------------------------------------------------------------------------------------------------------------- 回到頂部 一、修改設備樹
[單片機]
Linux下的觸摸屏驅動
一.觸摸屏理論概述 對于觸摸屏驅動,我們主要需要掌握觸摸屏驅動代碼和應用層測試代碼。下面講的是基于Mini2440的觸摸屏驅動,現在的驅動我們都將設備和驅動分離,掛在平臺設備總線上,讓設備和驅動去匹配。而我們在linu2.6.32.2內核版本中的觸摸屏驅動仍然沒有將設備和驅動分離,這樣就不存在匹配問題,這種現象其實我們并不陌生,在我們學習驅動的前期,都會研究簡單字符驅動代表LED驅動,那個驅動就是把設備和驅動寫在了一起。總結下,驅動和設備可以分離也可以不分離,建議分離,而本觸摸屏驅動沒有分離設備和驅動,有興趣可以將設備和驅動進行分離。 先說明下觸摸屏的工作原理,當有人在觸摸屏上按下觸筆時,觸摸屏的四個引腳會產生不同的電壓值,這
[單片機]
TQ2440 linux i2c驅動——at24c02(eeprom)
一.開發環境: (1)開發板:TQ2440開發板 (2)pc系統:ubuntu 13.04-amd64 (3)交錯編譯器:arm-linux-gcc version-4.3.3 (4)linux kernel:linux 2.6.30。4 二.i2c系統簡介 (這里稍微羅嗦幾句結構上的東西,摘抄自網絡) I2c是philips提出的外設總線.I2C只有兩條線,一條串行數據線:SDA,一條是時鐘線SCL.正因為這樣,它方便了工程人員的布線.另外,I2C是一種多主機控制總線.它和USB總線不同,USB是基于master-slave機制,任何設備的通信必須由主機發起才可以.而I2C是基于multi master機制.一同總線上可允許
[單片機]
TQ2440 <font color='red'>linux</font> i2c<font color='red'>驅動</font>——at24c02(eeprom)
iTOP-4412開發板驅動lcd顯卡以及linux開機log的修改方法
iTOP-4412 開發板 LCD 的屏幕驅動,iTOP-4412 開發板支持 4.3寸,7 寸,9.7 寸的 lcd 顯示屏。其中 4.3 寸屏是用的 cpu 直接出來的 RGB 信號,7 寸屏和 9.7寸屏是用的 LVDS 信號,硬件上使用了一個 RGB 轉 LVDS 的芯片實現的。我們來看下顯示驅動,顯示驅動在內核的“drivers/video/samsung”目錄下面,這個驅動是三星提供好的,我們這支只講下我們需要修改的幾個文件。 首先是關于屏幕的分辨率的修改, 因為不同的屏幕分辨率, 頻率以及其他一些硬件參數是不同的,所以我們需要根據這些參數去配置 cpu 的顯示控制器,關于這些參數是在“driversvideo/s
[單片機]
小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 承德县| 金川县| 榆中县| 龙陵县| 大石桥市| 忻城县| 霸州市| 辽源市| 获嘉县| 扶沟县| 桃源县| 临桂县| 八宿县| 永平县| 砚山县| 九龙县| 珠海市| 深圳市| 兰西县| 东宁县| 巴林右旗| 阿拉善盟| 鸡东县| 静海县| 崇信县| 花莲市| 红河县| 濮阳市| 清河县| 万山特区| 罗江县| 临沂市| 库伦旗| 铜川市| 武平县| 石门县| 彭水| 泸西县| 公主岭市| 融水| 仙桃市|