欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

miscdevice设备驱动应用-按键

程序员文章站 2022-06-08 19:17:19
...

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

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

miscdevice设备驱动应用-按键

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