电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
【i.MX6ULL】驱动开发7——按键输入捕获
分 享
扫描二维码分享
【i.MX6ULL】驱动开发7——按键输入捕获
i.MX6ULL
嵌入式
linux
码农爱学习
关注
发布时间: 2021-11-30
丨
阅读: 452
前面几篇文章,从最基础的寄存器点灯,到设备树点灯,再到GPIO子系统点灯,一步步了解嵌入式Linux开发的各种点灯原理。 点灯用到的都是GPIO的输出功能,这篇,通过按键的使用,来学习**GPIO输入功能**的使用。 # 1 硬件介绍 ## 1.1 板子上按键原理图 先来看**原理图**,我板子上有4个按键sw1~sw4: ### 1.1.1 SW1 **SW1**是板子的系统复位按键,不可编程使用 ![](https://cf02.ickimg.com/bbsimages/202111/ac10a52f2f57601ec6602e0428bd406c.png) ### 1.1.2 SW2、SW3 - **SW2**:SNVS_TAMPER1,GPIO5_1 平时是低电平,按下去是高电平。 - **SW3**:ONOFF 它也是系统级的按键,用于长按进行开关机。 ![](https://cf02.ickimg.com/bbsimages/202111/df8daeb7a524148cf7f20e7a64a8c77a.png) ### 1.1.3 SW4 **SW4**是BOOT_MODE1脚,用来进行串行烧录模式切换,需要再与复位键配合使用。 本篇仅测试按键功能,因此可以该按键。 ![](https://cf02.ickimg.com/bbsimages/202111/9bb92e170e07ba4dd40ef55eeb1e91f3.png) ### 1.1.4 使用其中2个按键 板子上这4个按键的功能特性如下表: ![](https://cf02.ickimg.com/bbsimages/202111/cddab73dd14ac77ca4042d6130955b67.png) 本实验使用SW2和SW4这两个按键来进行实验。 ![](https://cf02.ickimg.com/bbsimages/202111/f604d5bd1d1cf6ec4172c8c01fb646da.png) # 2 软件编写 ## 2.1 修改设备树文件 ### 2.1.1 修改iomuxc节点 修改imx6ull-myboard.dts,在iomuxc节点的imx6ull-evk字节点下创建一个名为pinctrl_key的子节点,节点内容如下: ```c pinctrl_key: keygrp { fsl,pins = < MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x3080 /@@* SW2 */ MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11 0xF080 /@@* SW4 */ >; }; ``` 这部分是对引脚进行配置,这两个引脚的定义是在imx6ull-pinfunc-snvs.h文件中: ![](https://cf02.ickimg.com/bbsimages/202111/f325cded8a40e9d059617eac67f357e9.png) 引脚宏定义后面的值,是对引脚功能的配置: SW2:0x3080,即0011 0000 1000 0000 SW4:0xF080,即1000 0000 1000 0000 对照之前讲解GPIO的[PAD寄存器的配置](https://www.icxbk.com/article/detail?aid=2375),根据两个按键的实际电路配置上拉或下拉。 ``` /@@* *bit 16:0 HYS关闭 *bit [15:14]: [00]下拉 [01]47k上拉 [10]100k上拉 [11]22k上拉 <--- *bit [13]: [0]kepper功能 [1]pull功能 *bit [12]: [0]pull/keeper-disable [1]pull/keeper-enable *bit [11]: 0 关闭开路输出 *bit [10:8]: 00 保留值 *bit [7:6]: 10 速度100Mhz *bit [5:3]: 000 输出disable <--- *bit [2:1]: 00 保留值 *bit [0]: 0 低转换率 */ ``` > 注:SW4 (MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11)这个GPIO,在设备中实际已经被其它设备(spi4)使用了。 > > 在imx6ull-myboard.dts的300多行处,有: > > ```c > pinctrl_spi4: spi4grp { > fsl,pins = < > MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1 > MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1 > MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1 > MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000 > >; > }; > ``` > > 理论上我们应该把这里的配置给注释掉,因为1个IO是不能同时进行2种功能的。由于本次实验不使用spi4,暂且也先不管它,看看会有什么影响,如果影响了本实验,再给把这里的配置给注掉。 ### 2.1.2 添加key节点 在根节点下创建名为key的按键节点,内容如下: ```c key { #address-cells = <1>; #size-cells = <1>; compatible = "myboard-key"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_key>; key1-gpio = <&gpio5 1 GPIO_ACTIVE_HIGH>; /@@* SW2 */ key2-gpio = <&gpio5 11 GPIO_ACTIVE_LOW>; /@@* SW4 */ status = "okay"; }; ``` ## 2.2 编写按键驱动程序 按键驱动,也属于字符设备驱动,和之前的字符设备驱动的框架一样,主要的修改点在按键的硬件初始化配置已经按键的读取。 新建一个key-Bsp.c ### 2.2.1 按键的硬件初始化 初始化的流程,就是使用OF函数来从设备树中获取key节点,然后使用GPIO子系统的API函数,将GPIO配置为输入。 ```c static int keyio_init(void) { keydev.nd = of_find_node_by_path("/key"); if (keydev.nd== NULL) { return -EINVAL; } keydev.key1_gpio = of_get_named_gpio(keydev.nd ,"key1-gpio", 0); keydev.key2_gpio = of_get_named_gpio(keydev.nd ,"key2-gpio", 0); if ((keydev.key1_gpio < 0)||(keydev.key2_gpio < 0)) { printk("can't get key\r\n"); return -EINVAL; } printk("key1_gpio=%d, key2_gpio=%d\r\n", keydev.key1_gpio, keydev.key2_gpio); /@@* 初始化key所使用的IO */ gpio_request(keydev.key1_gpio, "key1"); /@@* 请求IO */ gpio_request(keydev.key2_gpio, "key2"); /@@* 请求IO */ gpio_direction_input(keydev.key1_gpio); /@@* 设置为输入 */ gpio_direction_input(keydev.key2_gpio); /@@* 设置为输入 */ return 0; } ``` ### 2.2.2 读取按键的值 读取按键的值,也是GPIO子系统的API函数来读取。读取到按键的值后,将该值传递出来给应用层使用,注意这里使用了原子操作的方式atomic_set和atomic_read实现数据的写入和读取。 ```c /@@* 定义按键值 */ #define KEY1VALUE 0X01 /@@* 按键值 */ #define KEY2VALUE 0X02 /@@* 按键值 */ #define INVAKEY 0X00 /@@* 无效的按键值 */ static ssize_t key_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { int ret = 0; int value; struct key_dev *dev = filp->private_data; if (gpio_get_value(dev->key1_gpio) == 1) /@@* key1按下 */ { printk("get key1: high\r\n"); while(gpio_get_value(dev->key1_gpio)); /@@* 等待按键释放 */ atomic_set(&dev->keyvalue, KEY1VALUE); } else if (gpio_get_value(dev->key2_gpio) == 0) /@@* key2按下 */ { printk("get key2: low\r\n"); while(!gpio_get_value(dev->key2_gpio)); /@@* 等待按键释放 */ atomic_set(&dev->keyvalue, KEY2VALUE); } else { atomic_set(&dev->keyvalue, INVAKEY); /@@* 无效的按键值 */ } value = atomic_read(&dev->keyvalue); ret = copy_to_user(buf, &value, sizeof(value)); return ret; } ``` ## 2.3 编写按键应用程序 新建一个key-App.c 按键的应用层程序,主要就通过驱动程序提供的按键读取接口,来循环读取按键的值,并在按键按下时,将按键的值打印出来。 ```c /@@* 定义按键值 */ #define KEY1VALUE 0X01 #define KEY2VALUE 0X02 #define INVAKEY 0X00 int main(int argc, char *argv[]) { int fd, ret; char *filename; int keyvalue; if(argc != 2) { printf("Error Usage!\r\n"); return -1; } filename = argv[1]; /@@* 打开key驱动 */ fd = open(filename, O_RDWR); if(fd < 0) { printf("file %s open failed!\r\n", argv[1]); return -1; } /@@* 循环读取按键值数据! */ while(1) { read(fd, &keyvalue, sizeof(keyvalue)); if (keyvalue == KEY1VALUE) { printf("KEY1 Press, value = %#X\r\n", keyvalue); } else if (keyvalue == KEY2VALUE) { printf("KEY2 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; } ``` # 3 实验测试 ## 3.1 编译程序 ### 3.1.1 编译设备树 编译设备树文件,并将编译出的dtb文件复制到启动文件夹: ![](https://cf02.ickimg.com/bbsimages/202111/f087cd6a03b45cc2a284154372d15d4b.png) 网络方式启动开发板,查看key节点: ![](https://cf02.ickimg.com/bbsimages/202111/af1791bc3f6ee61e76775a9b5535bd30.png) ### 3.1.2 编译按键驱动程序 ![](https://cf02.ickimg.com/bbsimages/202111/7b26b2e6198568d6af339374b9feb50b.png) ### 3.1.3 编译按键应用程序 ![](https://cf02.ickimg.com/bbsimages/202111/13df64acc8c0e34491bc50e58aace61d.png) ## 3.2 测试 ![](https://cf02.ickimg.com/bbsimages/202111/cef404d13df1ea64802d9d54c081e700.png) ## 3.3 查看CPU占用率 先Ctrl+C结束掉此按键进程,然后使用如下指令来后台运行按键程序: ```sh ./key-App /dev/key & ``` 然后再使用指令: ```sh top ``` 来查看CPU是使用情况。从下图可以看出,此时CPU的使用率是99.8%,全被按键检查程序占用了,因为按键程序中有个while循环在一直读取按键的值。 ![](https://cf02.ickimg.com/bbsimages/202111/a9a47e84bf447e8d3f4372e9b4a91a46.png) 使用指令: ```sh ps ``` 查看按键的进程号,如下图为149,再使用: ```sh kill -9 149 ``` 来杀掉按键进程,然后再使用top指令查看,可以看到CPU的使用率又变回了0。 ![](https://cf02.ickimg.com/bbsimages/202111/31eee06a3c78830f1359a649527e1e1d.png) 实际的按键使用中,一般不会使用本篇的这种持续检测导致CPU占满的方式,本篇只是先来介绍GPIO的输入功能的使用,后续会使用更加高效的按键检测机制来实现按键检测功能。 # 4 总结 本篇主要介绍了i.MX6ULL的按键检测的使用,主要的知识点是设备树的修改,以及GPIO的输入配置与高低电平的读取。 ![](https://cf02.ickimg.com/bbsimages/202111/adc3835ee9df6f3c7e77009c4137be44.png)
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
码农爱学习
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交