按键驱动--定时器消抖

发布者:Chunjie2022最新更新时间:2016-04-01 来源: eefocus关键字:按键驱动  定时器消抖 手机看文章 扫描二维码
随时随地手机看文章
驱动源码:
#include "linux/module.h"
#include "linux/kernel.h"
#include "linux/fs.h"
#include "linux/init.h"
#include "linux/delay.h"
#include "linux/irq.h"
#include "asm/uaccess.h"
#include "asm/irq.h"
#include "asm/io.h"
#include "asm/arch/regs-gpio.h"
#include "asm/hardware.h"
#include "linux/poll.h"
 
int major = 0;
static struct class *keydrv_class;
static struct class_device *keydrv_class_dev;
volatile unsigned long *gpfcon;
volatile unsigned long *gpfdat;
 
volatile unsigned long *gpgcon;
volatile unsigned long *gpgdat;
 
struct pin_desc{
    unsigned int pin;
    unsigned int key_val;
};
 
struct pin_desc pins_desc[4] = {
    {S3C2410_GPF0, 0x01},
    {S3C2410_GPF2, 0x02},
    {S3C2410_GPG3, 0x03},
    {S3C2410_GPG11, 0x04},
};
 
// 键值: 按下时, 0x01, 0x02, 0x03, 0x04 
// 键值: 松开时, 0x81, 0x82, 0x83, 0x84 
static unsigned char key_val;
 
static struct timer_list   buttons_timer;
static struct pin_desc *irq_pd;
 
static DECLARE_MUTEX(button_lock);     //定义互斥锁
 
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
 
// 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 
static volatile int ev_press = 0;
 
static struct fasync_struct *button_async;
 
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
    irq_pd = (struct pin_desc *)dev_id;
    mod_timer(&buttons_timer,jiffies+HZ/100);   //10ms以后启动定时器
    return IRQ_RETVAL(IRQ_HANDLED);
}
static int key_drv_open(struct inode *inode, struct file *file)
{
      if(file->f_flags & O_NONBLOCK)
      {
            if(down_trylock(&button_lock))
                  return -EBUSY;
      }
      else
      {
            // 获取信号量 
            down(&button_lock);
      }
      request_irq(IRQ_EINT0, buttons_irq,IRQT_BOTHEDGE,"S2",&pins_desc[0]);
      request_irq(IRQ_EINT2, buttons_irq,IRQT_BOTHEDGE,"S3",&pins_desc[1]);
      request_irq(IRQ_EINT11,buttons_irq,IRQT_BOTHEDGE,"S4",&pins_desc[2]);
      request_irq(IRQ_EINT19,buttons_irq,IRQT_BOTHEDGE,"S5",&pins_desc[3]);
      return 0;
 
}
 
ssize_t key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    if(size != sizeof(key_val))
        return -EINVAL;
    
    if(file->f_flags & O_NONBLOCK)
    {
          if(!ev_press)
                return -EAGAIN;
    }
    else
    {
         // 如果没有按键动作, 休眠 
         wait_event_interruptible(button_waitq, ev_press);    
    }
 
    //如果有按键动作, 返回键值 
    copy_to_user(buf, &key_val, 1);
    
    ev_press = 0;
    
    return 1;
    
}
 
int key_drv_close(struct inode *inode, struct file *file)
{
    free_irq(IRQ_EINT0,  &pins_desc[0]);
    free_irq(IRQ_EINT2,  &pins_desc[1]);
    free_irq(IRQ_EINT11, &pins_desc[2]);
    free_irq(IRQ_EINT19, &pins_desc[3]);
    up(&button_lock);
    return 0;
}
 
static unsigned key_drv_poll(struct file *file, poll_table *wait)
{
    unsigned int mask = 0;
 
    poll_wait(file, &button_waitq, wait); // 不会立即休眠
    
    if (ev_press)
        mask |= POLLIN | POLLRDNORM;
    
    return mask;
}
 
static int key_drv_fasync (int fd, struct file *filp, int on)
{
      printk("driver: fifth_drv_fasync\n");
      return fasync_helper(fd, filp, on, &button_async);
}
 
static struct file_operations key_drv_fops = {
    .owner   =   THIS_MODULE,    // 这是一个宏,推向编译模块时自动创建的__this_module变量 
    .open    =   key_drv_open,     
    .read   = key_drv_read,
    .release =   key_drv_close,
    .poll    =   key_drv_poll,
    .fasync  =   key_drv_fasync,
};
 
static void buttons_timer_function(unsigned long data)
{
    struct pin_desc * pindesc = irq_pd;
    unsigned int pinval;
    if(!pindesc)
            return ;
    pinval = s3c2410_gpio_getpin(pindesc->pin);
    if(pinval)
    {
        // 松开 
        key_val = 0x80 | pindesc->key_val;
    }
    else
    {
        // 按下 
        key_val = pindesc->key_val;
    }
    
    ev_press = 1;                           // 表示中断发生了 
    wake_up_interruptible(&button_waitq);   // 唤醒休眠的进程 
    
    kill_fasync (&button_async, SIGIO, POLL_IN);
}
 
static int key_drv_init(void)
{
     init_timer(&buttons_timer);
     buttons_timer.function = buttons_timer_function;
     //buttons_timer.expires = 0;
     add_timer(&buttons_timer);
 
    major = register_chrdev(0, "key_drv", &key_drv_fops);
 
    keydrv_class = class_create(THIS_MODULE, "key_drv");
    
    keydrv_class_dev = class_device_create(keydrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); 
     //             /dev/buttons 
 
    gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    gpfdat = gpfcon + 1;
 
    gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    gpgdat = gpgcon + 1;
 
    return 0;
}
static void key_drv_exit(void)
{
    unregister_chrdev(major, "key_drv");
    class_device_unregister(keydrv_class_dev);
    class_destroy(keydrv_class);
    iounmap(gpfcon);
    iounmap(gpgcon);
    return 0;    
}
 
 
module_init(key_drv_init);
 
module_exit(key_drv_exit);
 
MODULE_LICENSE("GPL");
 
=================================================================
测试程序:
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdio.h"
#include "poll.h"
#include "signal.h"
#include "sys/types.h"
#include "unistd.h"
#include "fcntl.h"
 
int fd;
 
void my_signal_fun(int signum)
{
      unsigned char key_val;
      read(fd, &key_val, 1);
      printf("key_val: 0x%x\n", key_val);
}
 
int main(int argc, char **argv)
{
      int ret;
      fd = open("/dev/buttons", O_RDWR);
      if(fd < 0)
      {
            printf("can't open!\n");
            return -1;
      }
      while(1)
      {
            ret = read(fd, &key_val, 1);
            printf("key_val:0x%x,ret = %d",key_val,ret);
            //sleep(5);
      }
      return 0;
}
 
===============================================================
解析:
1、先定义一个定时器:static struct timer_list   buttons_timer;
2、再在key_drv_init函数中初始化定时器:
     init_timer(&buttons_timer);
     buttons_timer.function = buttons_timer_function;
     //buttons_timer.expires = 0;
     add_timer(&buttons_timer);
3、在按键中断中设置定时器时间:
     mod_timer(&buttons_timer,jiffies+HZ/100);   //10ms以后启动定时器
4、如果没有二次中断修改中断时间则10ms以后就会进入定时器中断函数,处理定时器中断。
 

关键字:按键驱动  定时器消抖 引用地址:按键驱动--定时器消抖

上一篇:LCD驱动(输入子系统)
下一篇:字符设备驱动程序之异步通知

推荐阅读最新更新时间:2024-03-16 14:49

Tiny210按键阻塞访问驱动
buttons.c驱动源码: #include linux/device.h #include linux/interrupt.h #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux/init.h #include linux/delay.h #include linux/irq.h #include asm/uaccess.h #include asm/irq.h #include asm/io.h #include mach/gpio.h #include linux/poll.h sta
[单片机]
51单片机教程:按键定时器(有延时的程序不是好程序
按键消抖原理 一、首先来回顾一下按键延时消抖 按键由于是机械结构,按下的时候难免产生抖动,一般抖动会在按下的时候与松开的时候产生,抖动时间大概是10ms 于是针对按键抖动就有了延时消抖的一种简单的解决方法: 二、按键消抖代码 方法一: 按下按键损耗的时间取决于按下按键到松开的时间,至少10ms,按下按键后CPU不再执行其他指令,直到按键松开,应用能力弱 代码作用:按下按键led状态取反,按下按键需要等待松开 #include reg51.h sbit key=P1^0; //定义key为P1.0 sbit led=P2^0; //定义LED为P2.0 void delay_ms(unsigned int t)
[单片机]
51单片机教程:<font color='red'>按键</font>的<font color='red'>定时器</font><font color='red'>消</font><font color='red'>抖</font>(有延时的程序不是好程序
Proteus8.8版本+ STM32F103驱动LCD1602显示程序+按键+ADC+串口
STM32F103仿真驱动点亮LCD1602 一、开发环境介绍 proteus 8.8 版本+ STM32CubeMX 4.18.0 程序基于keil集成开发环境编写,基于ST官方的HAL库。 STM32CubeMX pack版本 STM32CubeMX的版本 二、项目功能介绍 该项目程序中实现了 1、程序实现了LCD1602的点亮显示 2、程序中实现了STM32的AD采样 3、程序中实现了串口通信 4、程序中实现了按键控制操作 通过滑动变阻器加放大器改变输入值。后边加上lcd1602,初始化显示“光节点检测系统” 然后加个按键按下开始 显示“光功率值:(多少)dbm 这里的范围就0-100 通过调节前边电位器每次只变化一
[单片机]
Proteus8.8版本+ STM32F103<font color='red'>驱动</font>LCD1602显示程序+<font color='red'>按键</font>+ADC+串口
单片机驱动LED数码管,按键TM1638芯片学习心得
TM1638是带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。主要应用于冰箱、空调 、家庭影院等产品的高段位显示屏驱动。 因为步进电机实验需要用到按键,但家有婴儿,没用松香铬铁之类的(技术早就还给老师了,也没有条件 ),只好在网上找,找到一个由TM1638做成的成品,感觉做工还不错,就买了一个,但其带的程序一时没看懂,花了些时间进行学习,觉得好精妙,就想分享一下。 绝不是给别人打广告,这程序确实我理解了很久。 附件是它完整的程序。 调用实现程序主要是显示与按键值获取。 1.显示: 为什么是0xc0|add呢? 因为芯片说明有:高位都是11, 就
[单片机]
单片机<font color='red'>驱动</font>LED数码管,<font color='red'>按键</font>TM1638芯片学习心得
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved