linux驱动开发-8_按键

首先在imx6ull按键在GPIO1 的 io18

在设备树上添加好信息

还要检查该 io 口有没有被复用为别的功能,有的话注释掉。

&iomuxc

		pinctrl_key_1: key-1{
			fsl,pins = <
				MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080
			>;
		};

根文件下:

	key{
		compatible = "lakzhu,key";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_key_1>;
		key-gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
		status = "ok";
	};

更改完后编译并且下载到开发板。

驱动注册与卸载:

#define KEY_COUNT 1
#define KEY_NAME  "key"
 

static int __init key__init(void)
{

}
static void __exit key_exit(void)
{

}

module_init(key__init);
module_exit(key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lakzhu");

创建设备结构体:

struct key_dev{
    dev_t devid; 
    int major;
    int minor;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    struct device_node *nd;
    int key_gpio;
    atomic_t key_value;
};


struct key_dev key;

操作函数:

通过 gpio_get_value 来读取按键的值,若是为 0 就表示按下了,为 1 为未按下。当按键松开后,将结构体中的原子变量改为 key0 表示按下,反之则为 key1  这里 key0 与 key1 的值无意义,知识一个代表而已。

#define KEY0 0XF0   //有效
#define KEY1 0X00   //无效


static int key_open(struct inode *inode, struct file *filp)
{
    int ret = 0;
    filp->private_data = &key;
    return ret;
}

static int key_release(struct inode *inode, struct file *filp)
{
    int ret = 0;
    return ret;
}

static ssize_t key_write(struct file *filp, const char __user *buff, size_t count,loff_t *ppos)
{
    int ret = 0;
    return ret;
}

static ssize_t key_read(struct  file *filp, char __user *buff, size_t count, loff_t *ppos)
{
    struct key_dev *dev = filp->private_data;
    int ret = 0, value;
    if(gpio_get_value(dev->key_gpio) == 0){
        //按下 等待释放
        while(!gpio_get_value(dev->key_gpio));
        atomic_set(&dev->key_value, KEY0);
    }else{
        atomic_set(&dev->key_value, KEY1);
    }
    value = atomic_read(&dev->key_value);

    ret = copy_to_user(buff, &value, sizeof(value));

    return ret;
}

static const struct file_operations filp = {//连接 .c 文件的open write 与 key_open key_write等操作
    .owner = THIS_MODULE,
    .open = key_open,
    .release = key_release,
    .write = key_write,
    .read = key_read,
};

驱动初始化:

经典的字符设备初始化。


static int __init key__init(void)
{
    int ret=0;
    atomic_set(&key.key_value, KEY1);
    //初始化设备号
    if(key.major){
        key.devid = MKDEV(key.major, 0);
        ret = register_chrdev_region(key.devid, KEY_COUNT, KEY_NAME);
    }else{
        ret = alloc_chrdev_region(&key.devid, 0, KEY_COUNT, KEY_NAME);
        gpioled.major = MAJOR(gpioled.devid);
        gpioled.minor = MINOR(gpioled.devid);
    }

    if(ret < 0){
        ret = -EINVAL;
        goto fail_devid;
    }
    printk("maj:%d , min:%d",key.major, key.minor);
    // 初始化字符设备
    key.cdev.owner = THIS_MODULE; 
    cdev_init(&key.cdev, &filp);
    ret = cdev_add(&key.cdev, key.devid, KEY_COUNT);
    if(ret < 0){
        ret = -ENAVAIL;
        goto fail_dev;
    }

    //创建设备节点
    key.class = class_create(THIS_MODULE, KEY_NAME);
    if(IS_ERR(key.class)){
        ret = PTR_ERR(key.class);
        goto fail_class;
    }

    //获取设备
    key.device = device_create(key.class, NULL, key.devid, NULL, KEY_NAME);
    if(IS_ERR(key.device)){
        ret = PTR_ERR(key.device);
        goto fail_device;
    }

    ret = keyio_init(&key);
    if(ret < 0){
        goto fail_device;
    }
    return ret;
fail_device:
    class_destroy(key.class);
fail_class:
    cdev_del(&key.cdev);
fail_dev:
    unregister_chrdev_region(key.devid, KEY_COUNT);
fail_devid:
    return ret;
}

static void __exit key_exit(void)
{

    //删除字符设备
    cdev_del(&key.cdev);

    //注销设备
    unregister_chrdev_region(key.devid, KEY_COUNT);

     //删除设备
    device_destroy(key.class, key.devid);

    //删除类
    class_destroy(key.class);

    //删除gpio
    gpio_free(key.key_gpio);
}

设备树中gpio的获取:

获取节点中的按键设备的信息,将gpio设为输入。

static int keyio_init(struct key_dev *dev)
{
    int ret = 0;


    //获取设备节点
    dev->nd = of_find_node_by_path("/key");
    if(dev->nd == NULL){
        ret = -ENAVAIL;
        goto fail_nd;
    }

    //获取gpio信息
    dev->key_gpio = of_get_named_gpio(dev->nd, "key-gpios", 0);
    if(dev->key_gpio < 0){
        ret = -ENAVAIL;
        goto fail_gpio;
    }

    ret = gpio_request(dev->key_gpio, "key0");
    if(ret){
        ret = -ENAVAIL;
        printk("io request fail");
        goto fail_quest;
    }

    ret = gpio_direction_input(dev->key_gpio);
    if(ret){
        ret = -ENAVAIL;
        goto fail_input;
    }

    return ret;

fail_input:
    gpio_free(dev->key_gpio);
fail_quest:
fail_gpio:
fail_nd:
    device_destroy(dev->class, dev->devid);
    return ret;
}

keyApp.c 的编写:

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

#define KEY0 0XF0 //无效
#define KEY1 0X00 //有效

int main(int argc, char *argv[])
{
    int keyvalue;
    int fd, ret;
    char *filename;

    if(argc != 2){
        printf("error usage");
        return -1;
    }

    filename = argv[1];

    fd = open(filename, O_RDWR);
    if(fd < 0){
        printf("file open error:%s",argv[1]);
        return -1;
    }

	while(1) {
		read(fd, &keyvalue, sizeof(keyvalue));
		if (keyvalue == KEY0) {	/* KEY0 */
			printf("KEY0 Press, value = %#X\r\n", keyvalue);	/* 按下 */
		}
	}

    ret = close(fd);
    if(ret < 0){
		printf("file %s close failed!\r\n", argv[1]);
		return -1;
	}
	return 0;
}

结果展示:

这只是最基础的按键读取,练最基础消抖都没做,当然我们也只是学习一下驱动开发流程,按键处理已经在 stm32 中做过太多了,现在最主要的还是学习驱动开发思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值