7.查询方式获取按键值

目录

 

1.硬件操作:

1,看原理图:查找引脚定义。

2,设置 4 个引脚为输入引脚:

3,在 read 操作中,返回 4 个引脚的状态。

4,测试

2.驱动源码

3.测试源码


1.硬件操作:

1,看原理图:查找引脚定义。

查主板:

所以可以知道:

S2---->EINT0---->GPF0

S3---->EINT2---->GPF2

S4---->EINT11---->GPG3

S5---->EINT19---->GPF11

2,设置 4 个引脚为输入引脚:

从上面的原理图可以看到,低电平要从开关接地端输入。

要有电流流过,就是有压差,从上面的原理图上知道, KEY 一端接了高电平,当 KEY 没按下时,这个 KEY 接 2440 的引脚都是高电平。当 KEY 按键按下,就接通了地,这时这些引脚就返回 0 。

3,在 read 操作中,返回 4 个引脚的状态。

然后将状态值从内核空间拷贝到用户空间。当驱动测试程序读设备节点时,调用到驱动中的“second_drv_read()”函数。

4,测试

按键时间要足够长才会检测到,短按检测不到

抖动的很厉害。查询的按键方式因为里面有一个死循环 while,会占用 CPU 资源:

注:本来应该占用率接近100%,很奇怪,我测试尽然没有

所以查询的方式不可取。查询是连续去读取按键值,去比较值是否有变化。这种方法很耗资源。

2.驱动源码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.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/miscdevice.h>
#include <linux/device.h>
/*2.操作key*/
/*定义配置寄存器和数据寄存器指针*/
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;

volatile unsigned long *gpgcon = NULL;
volatile unsigned long *gpgdat = NULL;
/*2.1查看原理图和芯片数据手册*/
/*
S2---->EINT0---->GPF0----->[1:0]
S3---->EINT2---->GPF2----->[5:4]
S4---->EINT11---->GPG3----->[7:6]
S5---->EINT19---->GPF11----->[23:22]
GPFCON---->0x56000050------->00 = intput    
GPFDAT---->0x56000054------->0为高有效

GPGCON---->0x56000060------->00 = intput    
GPGDAT---->0x56000064------->0为高有效
*/
/*1.5文件操作方法集合具体实现*/
static int second_open(struct inode *pinode, struct file *pfile)
{
	/*2.3配置配置寄存器为输入*/
	/*先清零*/
	*gpfcon &= ~((0x3 << (0*2)) | (0x3 << (2*2)));
	*gpgcon &= ~((0x3 << (3*2)) | (0x3 << (11*2)));
	
	return 0;
}
static ssize_t second_read(struct file *pfile, char __user *buf, size_t size, loff_t *poff)
{
	unsigned char key_val[4];
	int regval;
	if(size != sizeof(key_val))
	{
		return -EINVAL;
	}
	regval = *gpfdat;
	key_val[0] = (regval & (1<<0))?1:0;
	key_val[1] = (regval & (1<<2))?1:0;

	regval = *gpgdat;
	key_val[2] = (regval & (1<<3))?1:0;
	key_val[3] = (regval & (1<<11))?1:0;
	copy_to_user(buf, key_val, sizeof(key_val));

	
	return sizeof(key_val);
}

#define SECOND_NAME "second_name"
struct class *second_class;
struct class_device *second_device_class;
/*1.3文件操作方法集合*/
static const struct file_operations second_chrdev_fops  =
{
	.owner 		= THIS_MODULE,
	.open 		= second_open,
	.read	    = second_read,
	
};


/*1.首先写好驱动摸版*/
/*注:
编译成模块时module_init和module_exit
编译到内核时: __init和__exit起作用
*/
int major;
static int __init second_chrdev_init(void)
{

	/*1.1注册杂项设备*/
	//早期经典字符设备,需手动创设备节点,一个主设备号只可以注册一次
	/*
	主设备号,当 major 传递 0 时候表示由内核自动分配一个可用的主设备号.
	设备名,不需要和/dev 下对应节点名相同
	早期经典字符设备需要手动创建设备
	如果应用使用的是的/dev/chrdev_name
	mknod /dev/chrdev_name c 252 0
  或mknod /dev/chrdev_name c 252 1
  或mknod /dev/chrdev_name c 252 x
但是mknod /dev/chrdev_name c 250 x
一旦主设备号不是252,即是节点名相同都是open fail
结论:应用程序寻找程序程序不是通过设备名,而是通过设备号
	*/
	/*
	注:这里的节点名不一定要和/dev下一致,这里注册是/proc/devices下的名字
	一旦注册成功改主设备下的次设备号全部用完
	*/
	major = register_chrdev(0, SECOND_NAME, &second_chrdev_fops);
	printk("<0>major = %d\n",major);
	/*
	自动创建设备文件结点
	类的所有者, 固定是 THIS_MODULE
	类名,随便,能有含义最好, 不是 /dev/ 下设备的名字。这个名字决定了/sys/class/name
	*/
	second_class = class_create(THIS_MODULE, "second");
	/* /dev/xyz */
	second_device_class = class_device_create(second_class, NULL, MKDEV(major, 0), NULL, "second_device");
	
	/*2.2将物理地址和虚拟地址进行映射*/
	//用ioremap(开始地址  结束大小)
	/*
	先映射gpfcon为虚拟地址,F寄存器:gpfcon:0x56000050 gpfcon:0x56000054  
	gpfcon:0x56000058  Reserved:0x5600005c,2440为32位CPU,所以4个4字节为16细字节,
	故这里映射16字节
	*/
	gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
	//这里指针+1是以上面unsigned long为单位的
	gpfdat = gpfcon + 1;

	gpgcon = (volatile unsigned long *)ioremap(0x56000060,16);
	//这里指针+1是以上面unsigned long为单位的
	gpgdat = gpgcon + 1;
	return 0;
}

static void __exit second_chrdev_exit(void)
{
	/*1.2注销杂项设备*/
	unregister_chrdev(major, SECOND_NAME);
	class_device_unregister(second_device_class);
	class_destroy(second_class);
	iounmap(gpfcon);
	iounmap(gpgcon);
}


module_init(second_chrdev_init);//模块安装时执行初始化函数
module_exit(second_chrdev_exit);//模块卸载时执行卸载函数
MODULE_LICENSE("GPL");

3.测试源码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define SECOND_DEV "/dev/second_device"
int main(int argc, char **argv)
{
	int fd = -1;
	int val = 0;
	unsigned char key_val[4];
	int cnt  = 0;

	fd = open(SECOND_DEV, O_RDWR);
	if(fd < 0)
	{
		printf("open fial\n");
		return -1;
	}

	while(1)
	{
		read(fd, key_val, sizeof(key_val));
		if(!key_val[0] || !key_val[1] || !key_val[2] || !key_val[3])
		{
			printf("%04d press is: key_val[0]:%d,key_val[1]:%d,key_val[2]:%d,key_val[3]:%d\n",cnt++,
				key_val[0],key_val[1],key_val[2],key_val[3]);
		}
		sleep(1);
	}
	
	
	return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值