miscdevice设备驱动应用-按键
程序员文章站
2022-06-08 19:17:19
...
按键的硬件原理比较简单,下面为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
推荐阅读
-
韦东山uboot_内核_根文件系统学习笔记5.8-第005课_字符设备驱动_第008节_第008节_字符设备驱动程序之中断方式的按键驱动_编写代码
-
嵌入式Linux字符设备驱动--按键驱动
-
字符设备驱动开发 Linux 设备号 字符设备驱动开发步骤 open 函数调用流程 设备号的组成 设备号的分配 Linux 应用程序对驱动程序的调用 字符设备注册与注销 实现设备的具体操作函数
-
linux 驱动开发之平台设备驱动设备树 input子系统的使用:按键中断驱动
-
S3C2440 字符设备驱动程序之中断方式的按键驱动_编写代码(七)
-
miscdevice设备驱动应用-按键
-
第18章 驱动开发之字符设备应用程序