按键驱动编写

简介: 按键驱动编写

硬件原理

640.png

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

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

640.png640.png

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

软件编写

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

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

#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的寄存器地址。

640.png

编译dts

640.png

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

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

640.png

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

编写按键驱动程序

key.c

#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

#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

#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

#ifndef __KEY_H#define __KEY_H
#endif


测试

640.png

测试OK!

号主:一枚机械专业本科生,经历了转行,从外包逆袭到芯片原厂的Linux驱动开发工程师,深入操作系统的世界,贯彻终身学习、终身成长的理念。平时喜欢折腾,寒冬之下,抱团取暖,期待你来一起探讨技术、搞自媒体副业,程序员接单和投资理财。【对了,不定期送闲置开发板、书籍、键盘等等】。

如果你想了解我的转行经验,欢迎找我交流~gongzhong号【哆哆jarvis】

一起不断探索自我、走出迷茫、找到热爱,希望和你成为朋友,一起成长~

相关文章
|
负载均衡 JavaScript 算法
Node.js 多进程的概念、原理、优势以及如何使用多进程来提高应用程序的性能和可伸缩性
Node.js 多进程的概念、原理、优势以及如何使用多进程来提高应用程序的性能和可伸缩性
254 1
|
7月前
|
人工智能 物联网 API
又又又上新啦!魔搭免费模型推理API支持DeepSeek-R1,Qwen2.5-VL,Flux.1 dev及Lora等
通过API接口进行标准化,能让开源模型以更加轻量和迅速的方式被开发者使用起来,并集成到不同的AI应用中。魔搭通过API-Inference,支持广大开发者无需本地的GPU和环境设置,就能轻松的依托不同开源模型的能力,展开富有创造力的尝试,与工具结合调用,来构建多种多样的AI应用原型。
703 7
|
敏捷开发 测试技术 持续交付
阿里云云效产品使用合集之怎么批量导出任务
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
9月前
|
安全 网络安全
gbase8a centos8(kylinv10)加载报登录 ftp失败报错530 Login incorrect 排查过程及解决办法
centos8(kylinv10)加载报登录 ftp失败报错530 Login incorrect 排查过程及解决办法
|
9月前
|
JSON API 数据格式
淘系等商品评论Json数据格式参考,API接口测试
通过以上示例和说明,你可以了解淘系商品评论的JSON数据结构和如何使用相关API接口获取评论数据。在实际操作中,你需要参考具体的API接口文档和开放平台的相关说明进行配置和调用。
|
11月前
|
编解码 前端开发 JavaScript
ThreeJs制作模型图片
这篇文章介绍了如何使用Three.js将一张图片转化为3D场景中的像素化模型,通过提取图片的像素颜色并将它们应用到3D立方体上,形成一种特殊的图像展示效果。
176 0
ThreeJs制作模型图片
|
JavaScript 前端开发
Vue学习之--------el与data的两种写法、MVVM模型、数据代理(2022/7/5)
这篇文章详细介绍了Vue中`el`和`data`的两种写法,解释了MVVM(Model-View-ViewModel)模型的基础知识,并探讨了数据代理的概念。文章通过代码实例和页面效果展示了这些概念的应用,还回顾了`Object.defineProperty`方法,并解释了Vue中如何实现数据代理。
Vue学习之--------el与data的两种写法、MVVM模型、数据代理(2022/7/5)
|
存储 芯片
键盘驱动程序设计
键盘驱动程序设计
247 0
|
JavaScript Java 测试技术
基于微信小程序的网约巴士订票平台+springboot+vue.js附带文章和源代码设计说明文档ppt
基于微信小程序的网约巴士订票平台+springboot+vue.js附带文章和源代码设计说明文档ppt
211 1
按键驱动-实现短按、长按、双击、长按抬起事件
按键驱动-实现短按、长按、双击、长按抬起事件