miscdevice设备驱动应用-按键

按键的硬件原理比较简单,下面为miscdevice设备实现单个按键驱动的例子。

1)硬件连接。通过一个上拉电阻将处理器的外部中断(或GPIO)引脚拉高,电阻的另一端连接按键并接地即可实现。如图1所示。KEY1 口平时是处于高电平,当按键被按下时,将产生下降沿,CPU可以依据中断下降沿按键被按下。

2) 按键“消抖”

所有按键、触摸屏等机械设备都存在一个固有的问题,那就是"抖动",按键从最初接通到稳定接通要经过数毫秒乃至数十毫秒,其间可能发生多次"接通―断开"的过程。因此仅仅依据中断被产生就认定有一次按键行为是很不准确的。如果不消除"抖动"的影响,一次按键可能被理解为多次按键。

消除按键抖动影响的方法是:在判断有键按下后,进行软件延时(如20ms,在延时过程中要屏蔽对应中断),再判断键盘状态,如果仍处于按键按下状态,则可以判定该按键被按下。

3)驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <mach/gpio.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/miscdevice.h>


#define    KEY_PIN  14    //注意修改! 对应开发板上的key灯引脚
#define    KEY      GPIOA(KEY_PIN)
#define    BUTTON_ON      0
#define    BUTTON_DOWN    1


static unsigned  int key_stat= 0;
static unsigned  int flag_int= 0;

static irqreturn_t irq_func(int irqno,void *arg)
{
    disable_irq_nosync(gpio_to_irq(KEY));
    mdelay(20);
    //gpio_direction_input(KEY);
    if(!(gpio_get_value(KEY)))
    {
         key_stat = 1;
         printk("%d\n",key_stat);
    }else  
    {
         key_stat = 0;
         printk("%d\n",key_stat);
    } 
    enable_irq(gpio_to_irq(KEY));
    return IRQ_HANDLED;
}


//打开设备文件时开启中断
static int myopen(struct inode *ind,struct file *fl)
{
    int ret;
    ret= request_irq(gpio_to_irq(KEY),irq_func,IRQF_TRIGGER_FALLING,"mykeyirq",NULL);
    if(ret<0)
        goto err0;
    printk("open\n"); 
    return 0;

err0:
    return ret;
}



static ssize_t myread(struct file *fl,char __user *buf,size_t len,loff_t *off)
{
    int ret;

    
    ret= copy_to_user(buf,&key_stat,sizeof(key_stat));
    //printk("%d\n",key_stat);
    //printk("read\n");
    key_stat = 0; 
    return sizeof(int)-ret;
}

//关闭设备文件时释放中断
static int myclose(struct inode *inode,struct file *fl)
{
    free_irq(gpio_to_irq(KEY),NULL);
    gpio_free(KEY);

    return 0;
}

static struct file_operations fops= {
    .owner = THIS_MODULE,
    .open  = myopen,
    .read = myread,
    .release= myclose,
};

static struct miscdevice tkdev = {
    .minor = MISC_DYNAMIC_MINOR, // 255
    .name = "tkdev",
    .fops = &fops,
};

static int __init test_init(void)
{
    printk("init\n"); 
    return misc_register(&tkdev);
    
}

static void __exit test_exit(void)
{
    misc_deregister(&tkdev);
    printk("eixt\n"); 
}

module_init(test_init);
module_exit(test_exit);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("jmlinux");
MODULE_DESCRIPTION("led");
MODULE_VERSION("v0.0");

4)Makefile


obj-m += test_key.o

KSRC :=/Allwinner_H3_sdk/uboot_kernel/orangepi_sdk/source/linux-3.4.112

export ARCH:= arm
export CROSS_COMPILE:=arm-linux-gnueabihf-

all:
	make -C $(KSRC) modules M=`pwd`

.PHONY : clean
clean:
	make -C $(KSRC) modules clean M=`pwd`

make后,加载test_key.ko

5)驱动测试文件app.c

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>


int main(void)
{
    int fd,ret=0;
    int key_stat=0;

    fd = open("/dev/tkdev", O_RDWR);
    if (fd < 0)
    {
        perror("open");
  
    }
   
    while (1)
    {  
          ret=read(fd,&key_stat,sizeof(key_stat));
          if(ret<0)
          {    perror("read");
          }
          //printf("%d\n",key_stat);
          if(key_stat==1)
          {
              printf("down\n");
          }   
     //sleep(1);     
    }
    close(fd);
    return 0;
}   

6)执行效果,每当按下按键时,显示down

[ 8625.357757] 1
down
[ 8625.781173] 1
down
[ 8626.224433] 1
down
[ 8626.488397] 1
down
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值