嵌入式开发记录 day29 查询方式获取按键值
1、查询方式使用while循环一直在等待,判断按键有没有按下
2、按键驱动
使用两个按键:Home和Back按键 HOME对应管脚-->UART_RING对应GPIO-->GPX1_1对应宏定义--->EXYNOS4_GPX1(1) Back对应管脚-->SIM_DET对应GPIO---->GPX1_2对应宏定义--->EXYNOS4_GPX1(2)
上层应用与底层驱动之间传递数据:
使用copy_to_user()和copy_from_user()来实现driver到user和user到driver的数据传送。 函数原型: unsigned long copy_to_user(void *to, const void __user *from, usigned long count); unsigned long copy_from_user(void __user *to, const void *from, usigned long count);
open()函数返回值获取文件句柄,驱动实现文件句柄返回
This is used by subsystems that don't want seekable file descriptors int nonseekable_open(struct inode *inode, struct file *filp) { filp->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); return 0; } This is used by subsystems that don't want seekable file descriptors
3、资源释放与设备准备
由于用到的是按键,按键本来在Linux内核中讯为已经做好了,所以使用的时候需要释放
make menuconfig, Device Drivers ---> Input device support ---> Keyboards ---> GPIO Buttons 取消这一项
注册平台设备:
arch/arm/mach-exynos/mach-itop4412.c 在该目录下,添加
struct platform_device s3c_device_pollkey_ctl = { .name = "pollkey", .id = -1, }; // 在下一个位置添加 &s3c_device_pollkey_ctl,
编译烧写内核;
4、上面做了设备注册,下面做驱动注册
用的头文件
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <linux/miscdevice.h> #include <linux/platform_device.h> #include <mach/regs-gpio.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/regulator/consumer.h> #include <linux/delay.h>
static int key_gpios[] = { EXYNOS4_GPX1(1), EXYNOS4_GPX1(2), }; #define DPRINTK(x...) printk("POLLKEY_CTL DEBUG:" x) #define DRIVER_NAME "pollkey" // 打开设备--->对应应用open()函数 int pollkey_open(struct inode *inode,struct file *filp) { DPRINTK("Device Opened Success!\n"); return nonseekable_open(inode,filp); // 返回文件描述符 } // 释放设备 int pollkey_release(struct inode *inode,struct file *filp) { DPRINTK("Device Closed Success!\n"); return 0; } // 读设备操作 --->对应应用read()函数 static ssize_t pollkey_read(struct file *filp, char __user *buff, size_t size, loff_t *ppos) { unsigned char key_value[2]; if(size != sizeof(key_value)){ return -1; } // 获取端口的值 key_value[0] = gpio_get_value(key_gpios[0]); key_value[1] = gpio_get_value(key_gpios[1]); // Linux内核数据拷贝到用户层 // 内核key_value中的数据拷贝至用户层的buff copy_to_user(buff,key_value,sizeof(key_value)); return 0; } // 文件操作结构体 static struct file_operations pollkey_ops = { .owner = THIS_MODULE, .open = pollkey_open, .release= pollkey_release, .read = pollkey_read, }; // 杂项字符设备结构体 用于注册设备 以及文件操作 static struct miscdevice pollkey_dev = { .minor = MISC_DYNAMIC_MINOR, .fops = &pollkey_ops, .name = "pollkey", }; static int pollkey_probe(struct platform_device *pdev) { int ret,i; char *banner = "pollkey Initialize\n"; printk(banner); // 初始化提示信息 //GPIO管脚设置 for(i=0;i<2;i++){ // 给每一个GPIO端口申请管脚 ret = gpio_request(key_gpios[i],"key_gpio"); // 将GPIO管脚设置为输入模式 s3c_gpio_cfgpin(key_gpios[i],S3C_GPIO_INPUT); // 不需要推挽 s3c_gpio_setpull(key_gpios[i],S3C_GPIO_PULL_NONE); } // 杂项字符设备注册 ret = misc_register(&pollkey_dev); return 0; } static int pollkey_remove (struct platform_device *pdev) { // 杂项设备卸载 misc_deregister(&pollkey_dev); return 0; } static int pollkey_suspend (struct platform_device *pdev, pm_message_t state) { DPRINTK("pollkey suspend:power off!\n"); return 0; } static int pollkey_resume (struct platform_device *pdev) { DPRINTK("pollkey resume:power on!\n"); return 0; } // 平台驱动结构体 static struct platform_driver pollkey_driver = { .probe = pollkey_probe, .remove = pollkey_remove, .suspend = pollkey_suspend, .resume = pollkey_resume, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, }, }; static int __init pollkey_init(void) { // 平台驱动注册 return platform_driver_register(&pollkey_driver); } static void __exit pollkey_exit(void) { // 驱动卸载 platform_driver_unregister(&pollkey_driver); } module_init(pollkey_init); module_exit(pollkey_exit); MODULE_LICENSE("Dual BSD/GPL");
5、编写应用读取获取按键值
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> int main() { int fd; unsigned char buffer[2]; char *read_key = "/dev/pollkey"; // 设备节点 /*O_RDWR只读打开,O_NDELAY非阻塞方式*/ if((fd = open(read_key,O_RDWR|O_NDELAY))<0){ printf("APP open %s failed\n",read_key); return -1; } printf("APP open %s success!\n",read_key); while(1){ read(fd,buffer,sizeof(buffer)); // 程序一直在这里读数据 if(!buffer[0] || !buffer[1]){ printf("key home value is %d\n",buffer[0]); printf("key back value is %d\n",buffer[1]); } } close(fd); }
6、驱动加载以后,可以查看下ls /dev下的设备;如果没有pollkey,那应用也打不开;查看设备注册、驱动程序;
7、加载应用
可以按HOME和Back键;
8、使用top命令 查看CPU占用情况,其他应用占用很少,readpollkey.o占了26%+;查询方式很消耗资源;