前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >按键驱动编写

按键驱动编写

作者头像
哆哆jarvis
发布2022-08-23 14:11:23
1.4K0
发布2022-08-23 14:11:23
举报
文章被收录于专栏:嵌入式进阶之路

硬件原理

从图中可以看到按键断开时,由于接了上拉电阻,所以CPU检测到默认是高电平的,当按键被按下时,电路导通,所以KEY0引脚变成低电平,即低电平有效。

那么按键是接到CPU哪个引脚呢?代码里需要操作该引脚。

通过在电路原理图中搜索KEY0,可以发现他是接到了UART1_CTS上,再搜索UART1_CTS,发现它接到了CPU的K15,做按键驱动我们需要将其复用为普通IO即可,即GPIO1_IO18,硬件电路分析完毕。

软件编写

这里采用kernel的dts,gpio和pinctrl子系统去完成对按键引脚的初始化和电平读取等。

修改imx6ull-14x14-evk.dts文件

代码语言:javascript
复制
#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"

/ {
`````省略`````
  key  {
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "key";
    pinctrl-name = "default";
    pinctrl-0 = <&pinctrl_key>;
    key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>; // 低电平有效
    status = "okay";
  }
`````省略`````
};
`````省略`````

&iomuxc_snvs {
  pinctrl-names = "default_snvs";
        pinctrl-0 = <&pinctrl_hog_2>;
        imx6ul-evk {
 `````省略`````
        pinctrl_key: keygrp {
            fsl,pin = <
            MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080
        >;
    };
 
        };
`````省略`````
};
`````省略`````

在根节点/下添加key节点,key节点调用pinctrl节点,设置GPIO1_IO18的寄存器地址。

编译dts

输入make dtbs,生成了一堆dtb文件,我用的是imx6ull-14x14-evk.dtb,将其拷贝到tftpboot目录下,我的板子使用tftpboot加载zImage和dtb文件。

如何判断刚刚添加的key设备节点是否有效?

进入/proc/device-tree, 可以查看到有key节点,说明添加成功。

编写按键驱动程序

key.c

代码语言:javascript
复制
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <linux/miscdevice.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

#include "key.h"

struct key_dev dev;

static int key_open(struct inode *nd, struct file *flip)
{
  flip->private_data = &dev;
  return 0;
}

static ssize_t key_read(struct file *flip, char __user *buf, size_t size, loff_t *offset)
{
  int isPress;
  int ret;

  isPress = gpio_get_value(dev.gpio);
  pr_info("[kernel] isPress=%d\n", isPress);
  ret = copy_to_user(buf, &isPress, sizeof(isPress));

  return ret;
}

static struct file_operations key_fops= {
  .owner = THIS_MODULE,
  .open = key_open,
  .read = key_read,
};

struct miscdevice key_miscdev = {
  .minor    = 143,
  .name    = "key",
  .fops    = &key_fops,
};

static int key_probe(struct platform_device * pdev)
{
  int err;

  dev.np = of_find_node_by_path("/key");
  if (!dev.np) {
    pr_err("can't find key in dts\n");
    return -EINVAL;
  }

  dev.gpio = of_get_named_gpio(dev.np, "key-gpio", 0);
  if (!gpio_is_valid(dev.gpio)) {
    return -ENODEV;
  }

  err = misc_register(&key_miscdev);
  if (err < 0) {
    pr_err("KEY error: cannot register device\n");
    return err;
  }

  return 0;
}

static int key_remove(struct platform_device *pdev)
{
  // 注销misc设备驱动
  (void)misc_deregister(&key_miscdev);
  return 0;
}

static const struct of_device_id key_of_match_table[] = {
  { .compatible = "key" },
  {},
};

static struct platform_driver key_drv = {
  .probe = key_probe,
  .remove = key_remove,
  .driver = {
    .owner = THIS_MODULE,
    .name = "key",
    .of_match_table = key_of_match_table,
  }
};

static int __init key_init(void)
{
  return platform_driver_register(&key_drv);
}

static void __exit key_exit(void)
{
  platform_driver_unregister(&key_drv);
}

module_init(key_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");

key.h

代码语言:javascript
复制
#ifndef __KEY_H
#define __KEY_H

struct key_dev {
  dev_t dev_id;
  struct cdev cdev;
  struct class *class;
  struct device *device;
  struct device_node *np;
  int gpio;
};

#endif

对misc进行简要说明,misc设备驱动是杂项设备驱动,它其实也是一种字符设备,可以理解成封装好了更多的步骤。正常我们注册一般的字符设备驱动需要以下步骤:

  1. alloc_chrdev_region // 注册字符设备驱动
  2. cdev_init
  3. cdev_add
  4. class_create //创建类
  5. device_create // 创建设备

而杂项设备只需一个函数搞定,杂项设备的minor也是可以用动态注册,自动分配。

应用层程序

key.c

代码语言:javascript
复制
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "sys/types.h"
#include "fcntl.h"
#include "sys/stat.h"
#include "key.h"

int main(int argc, char *argv[])
{
  char *filename = NULL;
  int fd = -1;
  char isPress;
  int ret;

  filename = argv[1];

  fd = open(filename, O_RDWR);
  if (fd < 0) {
    printf("open %s fail\n", filename);
    return -1;
  }

  ret = read(fd, &isPress, sizeof(isPress));
  if (ret < 0) {
    printf("read key value fail\n");
    close(fd);
    return -1;
  }

  if (isPress == 0)
    printf("key is press, isPress=%d\n", isPress);
  else
    printf("key is loosen, isPress=%d\n", isPress);

  close(fd);
  return 0;
}

key.h

代码语言:javascript
复制
#ifndef __KEY_H
#define __KEY_H

#endif

测试

测试OK!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 哆哆jarvis 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档