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

【改進定時器】IMX257實現GPIO-IRQ定時器消抖驅動程序

發布者:delta14最新更新時間:2024-08-16 來源: cnblogs關鍵字:定時器消抖  驅動程序 手機看文章 掃描二維碼
隨時隨地手機看文章

本文,我們還是在前面的按鍵驅動程序的基礎上,引入定時器,來消除抖動。

一、內核定時器詳解

1.timer_list結構體

在/include/linux/timer.h中。

struct timer_list {

   struct list_head entry;

    //定時器鏈表,用于存放軟定時器,該鏈表根據定時器expirex字段的值將它們分組存放。

   unsigned long expires;

  //定時器的到期時間,到達expires時間后,定時器將調用其成員函數function,其中將data字段作為function的參數。該字段表示的時間是以時間節拍為單位。例如如果你想定時一秒,則expires=jiffies+HZ*1。

  void (*function)(unsigned long); //定時器到時處理函數

  unsigned long data; //function 的參數

  struct tvec_t_base_s *base;

  #ifdef CONFIG_TIMER_STATS

    void *start_site;

    char start_comm[16];

    int start_pid;

  #endif

};

時鐘中斷的發生頻率設定為HZ,HZ是一個與體系結構無關的常數,在文件中定義,時鐘中斷對操作系統是非常重要的,當時鐘中斷發生時,將周期性地執行一些功能

 

2.初始化定時器

①init_timer

void init_timer(struct timer_list *timer)

{

  debug_timer_init(timer);

  __init_timer(timer);

}

 

static void __init_timer(struct timer_list *timer)

{

  timer->entry.next = NULL;

  timer->base = __raw_get_cpu_var(tvec_bases);

  #ifdef CONFIG_TIMER_STATS

    timer->start_site = NULL;

    timer->start_pid = -1;

    memset(timer->start_comm, 0, TASK_COMM_LEN);

  #endif

}

init_timer()函數被定義在kernel/timer.c中,實際上是將timer的entry的next指針置為NULL,為base字段賦值。

 

②. timer=TIMER_INITIALIZER(function,expires,data);

采用這種初始化方式,必須首先先寫好定時器處理函數function. TIMER_INITIALIZER宏的定義如下:

#define TIMER_INITIALIZER(_function, _expires, _data) {

  .entry = { .prev = TIMER_ENTRY_STATIC },

  .function = (_function),

  .expires = (_expires),

  .data = (_data),

  .base = &boot_tvec_bases,

}

其中boot_tcec_bases是在kernel/timer中定義的一個全局的tvec_t_base_s類型的變量。

 

③.DEFINE_TIMER(timer,function,expires,data);

定義并初始化定時器timer,功能和前面差不多

#define DEFINE_TIMER(_name, _function, _expires, _data)

  struct timer_list _name =

  TIMER_INITIALIZER(_function, _expires, _data)

 

④. setup_timer(&timer);

等同于前面,不過對base字段的賦值是調用了init_timer()函數。setup_timer()原型為:

static inline void setup_timer(struct timer_list * timer,void (*function)(unsigned long),unsigned long data)

{

  timer->function = function;

  timer->data = data;

  init_timer(timer);

}

 

 

3.注冊定時器

在定義并初始化了定時器之后,就要調用add_timer()函數來將該定時器注冊到內核中,這樣定時器才會工作。在注冊之后,定時器就開始計時,在到達時間expires時,執行回調函數function(->data)。add_timer()函數的原型為:

static inline void add_timer(struct timer_list *timer)

{

  BUG_ON(timer_pending(timer));

  __mod_timer(timer, timer->expires);

}

 

4.刪除定時器

int del_timer(struct timer_list *timer);

從內核中刪除已經注冊的定時器timer。如果該定時器是活動的,則返回1,否則返回0。

int del_timer(struct timer_list *timer)

{

  tvec_base_t *base;

  unsigned long flags;

  int ret = 0;

  timer_stats_timer_clear_start_info(timer);

  if (timer_pending(timer)) {

    base = lock_timer_base(timer, &flags);

    if (timer_pending(timer)) {

      detach_timer(timer, 1);

      ret = 1;

    }

    spin_unlock_irqrestore(&base->lock, flags);

  }

  return ret;

}

 

5.修改定時器時間

如果所給的要修改的時間等于定時器原來的時間并且定時器現在正處于活動狀態,則不修改,返回1,否則修改定時器時間,返回0。mod_timer()是一個非有效的更新處于活動狀態的定時器的時間的方法,如果定時器處于非活動狀態,則會激活定時器。在功能上,mod_timer()等價于:

del_timer(timer);

timer->expires=expires;

add_timer(timer);

 

int mod_timer(struct timer_list *timer, unsigned long expires)

{

  BUG_ON(!timer->function);

  timer_stats_timer_set_start_info(timer);

  if (timer->expires == expires && timer_pending(timer))

    return 1;

  return __mod_timer(timer, expires);

}

 

 

6.使用方法

1.創建定時器:struct timer_list my_timer;

2.初始化定時器:init_timer(&my_timer);

3.根據需要,設置定時器了:

my_timer.expires = jiffies + delay;

my_timer.data = 0;

my_timer.function = my_function;

4.激活定時器:add_timer(&my_timer);

 

7.實例解析

 

程序是在前面程序的基礎上修改的,(博文地址:http://www.cnblogs.com/lihaiyan/p/4295961.html)

為了結構更簡單,前面的程序使用了六個GPIO引腳,可能會相對復雜,為了更加堅定明了,此處簡化為一個GPIO引腳了,思路和前面差不多,這里就是使用GPIO2_10這個引腳

① 定義定時器

②在打開函數中初始化定時器,并且申請GPIO2_10中斷

③在中斷中修改定時器,并且激活定時器,則沒發生一次中斷則激活一次定時器達到消除抖動的目的

此處的中斷函數只有一個任務,就是激活定時器,然后將其他的功能均轉移至定時器調用的函數中。

④可以發現,在定時器中,將前面中斷中的功能全部實現了,一旦按鍵按下,接下來20ms內的抖動都無效,因為修改定時器無法修改已經激活的定時器,所以那20ms內高低電平的抖動都將無效,達到了消除抖動的功能

⑤編譯測試。結果如下圖所示:

附上驅動程序代碼:


  1 /******************************

  2     linux key_query

  3  *****************************/

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 #include

 15 #include

 16 #include //error: 'TASK_INTERRUPTIBLE' undeclared 

 17 #include

 18 #include

 19 

 20 #include 'mx257_gpio.h'

 21 #include 'mx25_pins.h'

 22 #include 'iomux.h'

 23 

 24 #define Driver_NAME 'key_interrupt'

 25 #define DEVICE_NAME 'key_interrupt'

 26 

 27 #define GPIO2_21    MX25_PIN_CLKO

 28 #define GPIO3_15    MX25_PIN_EXT_ARMCLK

 29 #define GPIO2_10    MX25_PIN_A24

 30 #define GPIO2_11    MX25_PIN_A25

 31 #define GPIO2_8     MX25_PIN_A22

 32 #define GPIO2_9     MX25_PIN_A23

 33 #define GPIO2_6     MX25_PIN_A20

 34 #define GPIO2_7     MX25_PIN_A21

 35 //command

 36 #define key_input     0

 37 #define version        1

 38 //定義各個按鍵按下的鍵值

 39 struct pin_desc{

 40     unsigned int pin;

 41     unsigned int key_val;

 42 };

 43 //當按鍵按下時,鍵值分別為 以下值

 44 struct pin_desc pins_desc[8] = {

 45     {GPIO2_6,    0x01},

 46     {GPIO2_7,    0x02},

 47     {GPIO2_8,    0x03},

 48     {GPIO2_9,    0x04},

 49     {GPIO2_10,    0x05},

 50     {GPIO2_11,    0x06},

 51     {GPIO2_21,    0x07},

 52     {GPIO3_15,    0x08},

 53 };

 54 struct pin_desc * pindesc;

 55 static int flag=0;

 56 //定義一個全局變量,用于保存按下的鍵值

 57 static unsigned int key_val;

 58 

 59 struct timer_list my_timer;

 60 unsigned int cnt_timer = 0;

 61 #define TIMER_DELAY_20MS  HZ/50

 62 

 63 //interrupt head

 64 static DECLARE_WAIT_QUEUE_HEAD(key_interrupt_wait);

 65 static volatile unsigned char ev_press;  

 66 

 67 static int major=0;

 68 

 69 //auto to create device node

 70 static struct class *drv_class = NULL;

 71 static struct class_device *drv_class_dev = NULL;

 72 

 73 void timer_function(unsigned long data){

 74     int index = data;

 75     cnt_timer ++;

 76     printk('<0>enter timer_%d__%d',index,cnt_timer);

 77     if(flag){

 78         //獲取按鍵鍵值

 79         gpio_direction_input(IOMUX_TO_GPIO(GPIO2_10));

 80         key_val = gpio_get_value(IOMUX_TO_GPIO(pindesc->pin));

 81         if(!key_val){

 82             key_val = pindesc->key_val;

 83             printk('<0>get key 0x%x',key_val);    

 84             printk('<0>KEY_DOWNn');

 85             flag = 0;

 86             ev_press = 1;

 87             wake_up_interruptible(&key_interrupt_wait);

 88         }

 89     }

 90 }

 91 /* 中斷程序key_irq */

 92 static irqreturn_t key_irq(int irq, void *dev_id)

 93 {

 94     pindesc = (struct pin_desc *)dev_id;

 95     //發生了中斷

 96     printk('<0>2_10function interrupt key_irq!nn');

 97     mod_timer(&my_timer, jiffies+HZ/50);

 98     flag = 1;

 99 

100     return IRQ_RETVAL(IRQ_HANDLED);

101 }

102 

103 

104 /* 應用程序對設備文件/dev/key_query執行open(...)時,

105  * 就會調用key_open函數*/

106 static int key_open(struct inode *inode, struct file *file)

107 {

108     printk('<0>function open 2_10! nn');

109 

110     init_timer(&my_timer);

111      my_timer.function = timer_function;

112     my_timer.expires = jiffies+HZ/50;

113       add_timer(&my_timer); //定時器應該在此時被啟動

114 

115     request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, 'key_GPIO2_10', &pins_desc[4]);

116     return 0;

117 }

118 

119 

120 

121 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

122 {

123     int ret;

124     if(filp->f_flags & O_NONBLOCK){

125         if(!ev_press)

126             return -EAGAIN;

127     }else{

128     //如果按鍵沒有按下,沒有中斷,休眠

129         wait_event_interruptible(key_interrupt_wait,ev_press);

130     }

131     ret = copy_to_user(buff,&key_val,sizeof(key_val));

132     if(ret){

133         ;

134     }

135     ev_press = 0;

136     return sizeof(key_val);

137 }

138 

139 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

140 {

141     printk('<0>function write!nn');

142     

143     return 1;

144 }

145 

146 static int  key_release(struct inode *inode, struct file *filp)

[1] [2]
關鍵字:定時器消抖  驅動程序 引用地址:【改進定時器】IMX257實現GPIO-IRQ定時器消抖驅動程序

上一篇:IMX257 linux設備驅動之Cdev結構
下一篇:【改進信號量】IMX257實現GPIO-IRQ中斷按鍵獲取鍵值驅動程序

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

定時器實現按鍵
消除抖動的實現方法 在發生中斷后,延時一段時間(抖動時間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
[單片機]
用<font color='red'>定時器</font>實現按鍵<font color='red'>消</font><font color='red'>抖</font>
mini2440 簡單按鍵中斷模式驅動程序
Makefile KERN_DIR = /home/grh/kernel_source_code/linux-2.6.32.2 all : make -C $(KERN_DIR) M=`pwd` modules arm-linux-gcc key_interrupt_app.c -o key_interrupt_app clean : make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += key_interrupt.o copy : cp key_interrupt.ko key_interrupt_app
[單片機]
mini2440 簡單按鍵中斷模式<font color='red'>驅動程序</font>
漢字液晶FYD12864驅動程序
近期在一個項目中用到了帶漢字字庫的液晶FYD12864-0402B,此液晶可用串口操作,極限情況下只需要2根IO口驅動,原以為會很復雜,經弄懂后發現驅動非常方便。現將測試程序公布如下,但愿能起到拋磚引玉的作用。 /**************************************** ** 漢字液晶FYD12864測試程序 ** ** 文 件 名: main.c ** ** 主控芯片:M16 ** ** 晶振頻率:7.3728MHZ外部 ** ****************************************/ #include #include #include delay_jg.h #include
[單片機]
基于MCP2515的Linux CAN總線驅動程序設計
1.前言 CAN(Controller Area Network)總線,即控制器局域網總線,是一種有效支持分布式控制或實時控制的串行通信網絡。由于其高性能、高可靠性、及獨特的設計和適宜的價格而廣 泛應用于工業現場控制、智能樓宇、醫療器械、交通工具以及傳感器等領域,并已被公認為幾種最有前途的現場總線之一。CAN總線規范已經被國際標準化組織制 訂為國際標準ISO11898,并得到了眾多半導體器件廠商的支持。 本文使用華清遠見FS2416平臺。FS2416使用Socket網絡設備驅動和字符設備驅動兩種方式向Linux內核提供MCP2515的驅動,本文詳細介紹了使用Socket方式設計的基于MCP2515的Linux CAN
[單片機]
基于MCP2515的Linux CAN總線<font color='red'>驅動程序</font>設計
基于WinCE6.0的LPC3250串口驅動程序開發
引 言 Windows CE是一個開放的、可升級、可裁減的32位實時嵌入式操作系統,具有可靠性好、實時性高、內核體積小的特點,廣泛應用于工業控制、信息家電、移動通信、汽車電子、個人電子消費品等領域。最新版本Windows Em-bedded CE 6.0于2006年11月發布,其特點有:最大進程數量到32K,且每個進程有最大2 GB的虛擬內存空間;將關鍵的驅動程序、文件系統和圖形界面管理器移到了內核中,大大減少了CPU在內核態和用戶態間切換造成的性能損失等。 LPC3250是NXP半導體公司(由Philips公司成立)推出的帶有矢量浮點協處理器的ARM926EJ-SCPU內核的微控制器。它具有豐富的外圍接口,包括7個UART,其
[單片機]
基于WinCE6.0的LPC3250串口<font color='red'>驅動程序</font>開發
基于PCI總線的數字衛星解調卡驅動程序開發
   引言   PCI總線(即外圍部件互連總線)是Intel公司提出的計算機接口總線。它的時鐘頻率為33MHz,有32位數據總線,可支持突發傳輸模式,數據傳輸峰值速率高達132 MB/s。此外,PCI總線還可擴展為64位數據總線,擴展后的數據傳輸峰值速率高達264 MB/s,并支持即插即用功能而且獨立于處理器。由于PCI總線具有諸多優點,它已經成為PC機的標準總線。因此,PCI接口設備的驅動程序開發就顯得尤為重要。   數字衛星解調卡主要用于接收衛星發來的調制信號的數字解調。設計中的橋接芯片可采用PLX公司的PCI9054。本文主要介紹數字衛星解調卡的WDM驅動程序開發方法。    1 PCI9054接口芯片   PCI90
[電源管理]
基于PCI總線的數字衛星解調卡<font color='red'>驅動程序</font>開發
基于DSP的視頻采集驅動程序的設計
視頻終端的核心是圖像的數字化處理模塊。基于PC機的數字視頻處理,給出了算法研究的途徑,而基于高速DSP的應用模塊才提供了實時嵌入式視頻處理的可能。然而,基于DSP的海量視頻數據的實時處理的關鍵則是實時、合理的視頻數據采集。本文針對自行研制的基于 TMS320DM642 (以下簡稱DM642)DSP的視頻處理板卡,使其在C64x系列DSP的實時操作系統DSP/BIOS的環境下運行,實現基于類/微驅動模型的視頻采集驅動程序,并進一步描述采用EDMA(增強的直接存儲器存取控制器)的數字視頻圖像信號的實時傳輸。   1 類/微驅動程序模型   C64x系列的DSP系統給出了類/微驅動模型 的驅動程序結構,采用該模型進行驅動程序設計
[工業控制]
基于DSP的視頻采集<font color='red'>驅動程序</font>的設計
小廣播
設計資源 培訓 開發板 精華推薦

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

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

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 禄丰县| 龙海市| 醴陵市| 乐陵市| 都匀市| 观塘区| 灵武市| 徐汇区| 绥宁县| 莎车县| 义乌市| 商水县| 自治县| 江城| 新沂市| 龙州县| 渝中区| 思茅市| 宝坻区| 昂仁县| 乐业县| 香河县| 建水县| 婺源县| 承德市| 德阳市| 金湖县| 宾川县| 六安市| 台中市| 临沂市| 宁蒗| 仁化县| 绥滨县| 盐亭县| 荣昌县| 谷城县| 新密市| 安义县| 宣威市| 湖州市|