嵌入式开发记录 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%+;查询方式很消耗资源;

 

posted @ 2020-08-11 00:08  笑不出花的旦旦  阅读(344)  评论(0)    收藏  举报