Linux 按键输入实验

    在前几章我们都是使用的 GPIO 输出功能,还没有用过 GPIO 输入功能,本章我们就来学
习一下如果在 Linux 下编写 GPIO 输入驱动程序。 I.MX6U-ALPHA 开发板上有一个按键,我们
就使用此按键来完成 GPIO 输入驱动程序,同时利用第四十七章讲的原子操作来对按键值进行
保护。
49.1 Linux 下按键驱动原理
按键驱动和 LED 驱动原理上来讲基本都是一样的,都是操作 GPIO,只不过一个是读取
GPIO 的高低电平,一个是从 GPIO 输出高低电平。本章我们实现按键输入,在驱动程序中使用
一个整形变量来表示按键值,应用程序通过 read 函数来读取按键值,判断按键有没有按下。在
这里,这个保存按键值的变量就是个共享资源,驱动程序要向其写入按键值,应用程序要读取
按键值。所以我们要对其进行保护,对于整形变量而言我们首选的就是原子操作,使用原子操
作对变量进行赋值以及读取。 Linux 下的按键驱动原理很简单,接下来开始编写驱动。
注意,本章例程只是为了演示 Linux 下 GPIO 输入驱动的编写,实际中的按键驱动并不会
采用本章中所讲解的方法, Linux 下的 input 子系统专门用于输入设备!

49.3 实验程序编写
本实验对应的例程路径为: 开发板光盘-> 2、 Linux 驱动例程-> 11_key。
49.3.1 修改设备树文件
1、添加 pinctrl 节点
I.MX6U-ALPHA 开发板上的 KEY 使用了 UART1_CTS_B 这个 PIN,打开 imx6ull-alientekemmc.dts,在 iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“ pinctrl_key”的子节点,节点
内容如下所示:
示例代码 49.3.1.1 按键 pinctrl 节点
1 pinctrl_key: keygrp {
    2 fsl,pins = <
            3 MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080 /* KEY0 */
        4 >;
5 };3 行,将 GPIO_IO18 这个 PIN 复用为 GPIO1_IO18。

2、添加 KEY 设备节点
在根节点“ /”下创建 KEY 节点,节点名为“ key”,节点内容如下:
示例代码 49.3.1.2 创建 KEY 节点
1 key {
    2 #address-cells = <1>;
    3 #size-cells = <1>;
    4 compatible = "atkalpha-key";
    5 pinctrl-names = "default";
    6 pinctrl-0 = <&pinctrl_key>;
    7 key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>; /* KEY0 */
    8 status = "okay";
9 };6 行, pinctrl-0 属性设置 KEY 所使用的 PIN 对应的 pinctrl 节点。
第 7 行, key-gpio 属性指定了 KEY 所使用的 GPIO。

3、检查 PIN 是否被其他外设使用
在本章实验中蜂鸣器使用的 PIN 为 UART1_CTS_B,因此先检查 PIN 为 UART1_CTS_B 这
个 PIN 有没有被其他的 pinctrl 节点使用,如果有使用的话就要屏蔽掉,然后再检查 GPIO1_IO18
这个 GPIO 有没有被其他外设使用,如果有的话也要屏蔽掉。
设备树编写完成以后使用“ make dtbs”命令重新编译设备树,然后使用新编译出来的
imx6ull-alientek-emmc.dtb 文件启动 Linux 系统。启动成功以后进入“ /proc/device-tree”目录中
查看“ key”节点是否存在,如果存在的话就说明设备树基本修改成功

49.3.2 按键驱动程序编写
设备树准备好以后就可以编写驱动程序了,新建名为“ 11_key”的文件夹,然后在 11_key
文件夹里面创建 vscode 工程,工作区命名为“ key”。工程创建好以后新建 key.c 文件,在 key.c
里面输入如下内容:
示例代码 49.3.2.1 key.c 文件代码
略
第 36~46 行,结构体 key_dev 为按键的设备结构体,第 45 行的原子变量 keyvalue 用于记录按键值。
第 56~74 行,函数 keyio_init 用于初始化按键,从设备树中获取按键的 gpio 信息,然后设
置为输入。将按键的初始化代码提取出来,将其作为独立的一个函数有利于提高程序的模块化设计。
第 83~94 行, key_open 函数通过调用 keyio_init 函数来始化按键所使用的 IO,应用程序
每次打开按键驱动文件的时候都会初始化一次按键 IO。
第 104~120 行, key_read 函数,应用程序通过 read 函数读取按键值的时候此函数就会执
行。第 110 行读取按键 IO 的电平,如果为 0 的话就表示按键按下了,如果按键按下的话第
111 行就等待按键释放。按键释放以后标记按键值为
第 135~171 行,驱动入口函数,第 138 行调用 atomic_set 函数初始化原子变量默认为无效值。
第 178~186 行,驱动出口函数。
key.c 文件代码很简单,重点就是 key_read 函数读取按键值,要对 keyvalue 进行保护。

49.3.3 编写测试 APP
新建名为 keyApp.c 的文件,然后输入如下所示内容:
示例代码 49.3.2.2 keyApp.c 文件代码
第 51~56 行,循环读取/dev/key 文件,也就是循环读取按键值,并且将按键值打印出来。

49.4 运行测试
49.4.1 编译驱动程序和测试 APP
1、编译驱动程序
编写 Makefile 文件,本章实验的 Makefile 文件和第四十章实验基本一样,只是将 obj-m 变
量的值改为 key.o, Makefile 内容如下所示:
示例代码 49.4.1.1 Makefile 文件
1 KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imxrel_imx_4.1.15_2.1.0_ga_alientek
......
4 obj-m := key.o
......
11 clean:
12 $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
第 4 行,设置 obj-m 变量的值为 key.o。
输入如下命令编译出驱动模块文件:
make -j32
编译成功以后就会生成一个名为“ key.ko”的驱动模块文件。
2、编译测试 APP
输入如下命令编译测试 keyApp.c 这个测试程序:
arm-linux-gnueabihf-gcc keyApp.c -o keyApp

49.4.2 运行测试
将上一小节编译出来的 key.ko 和 keyApp 这两个文件拷贝到 rootfs/lib/modules/4.1.15 目录
中,重启开发板,进入到目录 lib/modules/4.1.15 中,输入如下命令加载 key.ko 驱动模块:
depmod //第一次加载驱动的时候需要运行此命令
modprobe key.ko //加载驱动
驱动加载成功以后如下命令来测试:
./keyApp /dev/key
当我们按下 KEY0 以后就会打印出“ KEY0 Press, value = 0XF0”,
表示按键按下。但是大家可能会发现,有时候按下一次 KEY0 但是会输出好几行“ KEY0 Press,
value = 0XF0”,这是因为我们的代码没有做按键消抖处理。
如果要卸载驱动的话输入如下命令即可:
rmmod key.ko

参考文献

【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.3.pdf

猜你喜欢

转载自blog.csdn.net/liurunjiang/article/details/107459513