rk3568按键输入


前言

本文记录的是按键按键输入实验


一、硬件原理图

按键实验实际上是操作GPIO,读取IO电平。
在这里插入图片描述
默认情况下 GPIO3_C5 是低电平,所以我们通过使用杜邦线将图 13.2.1 中 GPIO3_C5 这个引脚接到 VCC 上的方式来模拟按键按下。也就是模拟按键按下,GPIO3_C5 为高电平,松开按键为低电平。

二、修改设备树文件

rk3568-pinctrl.dtsi

	key-gpios{
		key_gpio: key-pin {
			rockchip,pins =
				<3 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>;
		};
	};

rk3568-atk-evb1-ddr4-v10.dtsi

	key {
		compatible = "alientek,key";
		pinctrl-names = "alientek,key";
		pinctrl-0 = <&key_gpio>;
		key-gpio = <&gpio3 RK_PC5 GPIO_ACTIVE_HIGH>;
		// interrupt-parent = <&gpio3>;
		// interrupts = <21 IRQ_TYPE_EDGE_BOTH>;
		status = "okay";
	};

key-gpio 属性指定了 KEY 所使用的 GPIO,高电平有效

实验

设置GPIO为输入模式
按键检测思路:
①按下检测:若为高电平,延时200ms消抖,确认是否真的为高电平
②松手检测:等待低电平到来,若为低电平,延时200ms消抖,确认是低电平后,再上报数据给应用。
代码:key.c

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define KEY_CNT      		1           	/* 设备号个数 */
#define KEY_NAME        	"key" 	        /* 名字 */
#define KEY_PRESS           0x0F            /* 按键被按下 */
#define INVAKEY             0x00            /* 按键松开 */
#define GPIO_HIGH_LEVEL     (1)
#define GPIO_LOW_LEVEL      (0)

struct key_dev
{
    dev_t devid;          		/* 设备号 */
    struct cdev cdev;    		/* cdev */
    struct class *class;  	    /* 类 */
    struct device *device;  	/* 设备 */
    int major;              	/* 主设备号 */
    int minor;              	/* 次设备号 */
    struct device_node  *nd;    /* 设备节点 */
    int key_gpio;           	/* key所使用的GPIO编号 */    
    atomic_t key_val;			    /* 原子变量 */
};

struct key_dev key;


static int key_drv_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &key; /* 设置私有数据 */

    return 0;
}


static ssize_t key_drv_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    int ret = 0;
    struct key_dev* p_key = filp->private_data;
    int key_gpio_val = gpio_get_value(p_key->key_gpio);
    if(key_gpio_val < 0) {
        return -1;
    } else if(key_gpio_val == GPIO_LOW_LEVEL) {
        atomic_set(&p_key->key_val, INVAKEY);
    } else if(key_gpio_val == GPIO_HIGH_LEVEL) {
        mdelay(200);
        if(gpio_get_value(p_key->key_gpio) == GPIO_HIGH_LEVEL) {
            while(gpio_get_value(p_key->key_gpio) == GPIO_HIGH_LEVEL);
            mdelay(200);
            if(gpio_get_value(p_key->key_gpio) == GPIO_LOW_LEVEL) {
                atomic_set(&p_key->key_val, KEY_PRESS);
            }
            
        }
        
    }

    ret = copy_to_user(buf, &p_key->key_val, sizeof(p_key->key_val));
    return 0;
}


static ssize_t key_drv_write(struct file *filp, const char __user *buf, 
		                         size_t cnt, loff_t *offt)
{

    return 0;
}


static int key_drv_realse(struct inode *inode, struct file *filp)
{
    // struct key_dev *dev = filp->private_data;

    return 0;
}

static const struct file_operations key_drv_ops = {
	.owner = THIS_MODULE,
	.open = key_drv_open,
	.read = key_drv_read,
    .write = key_drv_write,
	.release = key_drv_realse,
};


int key_parse_dts(void)
{
    int ret = 0;
    const char *str = NULL;

    /* 设置KEY所使用的GPIO */
    /* 1、获取设备节点:key */
    key.nd = of_find_node_by_path("/key");
    if(key.nd == NULL) {
        printk("key node not find!\r\n");
        return -EINVAL;
    }

    /* 2.读取status属性 */
    ret = of_property_read_string(key.nd, "status", &str);
    if(ret < 0) 
        return -EINVAL;

    if (strcmp(str, "okay"))
        return -EINVAL;
    
    /* 3、获取compatible属性值并进行匹配 */
    ret = of_property_read_string(key.nd, "compatible", &str);
    if(ret < 0) {
        printk("key: Faikey to get compatible property\n");
        return -EINVAL;
    }

    if (strcmp(str, "alientek,key")) {
        printk("key: Compatible match faikey\n");
        return -EINVAL;
    }

    /* 4、 获取设备树中的gpio属性,得到KEY所使用的KEY编号 */
    key.key_gpio = of_get_named_gpio(key.nd, "key-gpio", 0);
    if(key.key_gpio < 0) {
        printk("can't get key-gpio");
        return -EINVAL;
    }
    printk("key-gpio num = %d\r\n", key.key_gpio);

    /* 5.向gpio子系统申请使用GPIO */
    ret = gpio_request(key.key_gpio, "KEY-GPIO");
    if (ret) {
        printk(KERN_ERR "key: Faikey to request key-gpio\n");
        goto free_gpio;
    }

    /* 6、设置GPIO为输入 */
    ret =  gpio_direction_input(key.key_gpio);
    if(ret < 0) {
        goto free_gpio;
    }
    return 0;

free_gpio:
    gpio_free(key.key_gpio);
    return -EIO;
}


static int __init key_drv_init(void)
{
    int ret = 0;
	printk("key init\n");

	/* 原子变量初始值为1 */
	atomic_set(&key.key_val, INVAKEY);

    /* 注册字符设备驱动 */
    /* 1、创建设备号 */
    if (key.major) {        /*  定义了设备号 */
        key.devid = MKDEV(key.major, 0);
        ret = register_chrdev_region(key.devid, KEY_CNT, KEY_NAME);
        if(ret < 0) {
            pr_err("cannot register %s char driver [ret=%d]\n", KEY_NAME, KEY_CNT);
            goto dev_id_err;
        }
    } else {                        /* 没有定义设备号 */
        ret = alloc_chrdev_region(&key.devid, 0, KEY_CNT, KEY_NAME);    /* 申请设备号 */
        if(ret < 0) {
            pr_err("%s Couldn't alloc_chrdev_region, ret=%d\r\n", KEY_NAME, ret);
            goto dev_id_err;
        }
        key.major = MAJOR(key.devid); /* 获取分配号的主设备号 */
        key.minor = MINOR(key.devid); /* 获取分配号的次设备号 */
    }
    printk("key major=%d, minor=%d\r\n",key.major, key.minor);   
    
    /* 2、初始化cdev */
    key.cdev.owner = THIS_MODULE;
    cdev_init(&key.cdev, &key_drv_ops);
    
    /* 3、添加一个cdev */
    cdev_add(&key.cdev, key.devid, KEY_CNT);
    if(ret < 0)
        goto del_unregister; 

    /* 4、创建类 */
    key.class = class_create(THIS_MODULE, KEY_NAME);
    if (IS_ERR(key.class)) {
        goto del_cdev;
    }

    /* 5、创建设备 */
    key.device = device_create(key.class, NULL, key.devid, NULL, KEY_NAME);
    if (IS_ERR(key.device)) {
        goto destroy_class;
    }

    if(key_parse_dts() != 0) {
        goto destroy_class;
    }

    return 0;
    
destroy_class:
    class_destroy(key.class);
del_cdev:
    cdev_del(&key.cdev);
del_unregister:
    unregister_chrdev_region(key.devid, KEY_CNT);
dev_id_err:
	return -EIO;
}


static void __exit key_drv_exit(void)
{
	printk("key exit\n");

    /* 释放GPIO 	*/
    gpio_free(key.key_gpio); 

    /* 注销字符设备驱动 */
    device_destroy(key.class, key.devid);/* 注销设备 */
    class_destroy(key.class);/* 注销类 		*/
    cdev_del(&key.cdev);/*  删除cdev */
    unregister_chrdev_region(key.devid, KEY_CNT);
    
    return ;
}


module_init(key_drv_init);
module_exit(key_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lizh");



应用程序:keyApp.c

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"

#define KEY_PRESS           0x0F            /* 按键被按下 */
#define INVAKEY             0x00            /* 按键松开 */

#define		DRV_PATH_NAME 		"/dev/key"

int main(int argc, char *argv[])
{
	int i = 0, count = 0;
	int fd = 0;
	int ret = 0;
	int key_val = 0;

	/* 判断参数是否正确 */
	if(argc != 2) {
		printf("user param error!\n");
		printf("please input ./keyApp %s\r\n" , DRV_PATH_NAME);
		goto input_error;
	}

	/* 打开文件 */
	fd = open(DRV_PATH_NAME, O_RDWR);
	if(fd < 0) {
		goto open_failed;
	}

	while(1) {
		ret = read(fd, &key_val, sizeof(key_val));
		if(ret < 0) {
			goto read_error;
		}

		if(key_val == KEY_PRESS) {
			printf("key press down\n");
		} 
	}


	close(fd);
	return 0;

read_error:
	close(fd);
open_failed:
input_error:
	return -1;

}

结果图:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

free(me)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值