iMX6ULL —按键输入捕获与GPIO输入配置与高低电平读取

news2024/12/26 0:04:27

硬件介绍

1.1 板子上按键原理图

先来看原理图,我板子上有4个按键sw1~sw4:

1.1.1 SW1

SW1是板子的系统复位按键,不可编程使用

1.1.2 SW2、SW3

SW2:SNVS_TAMPER1,GPIO5_1

平时是低电平,按下去是高电平。

SW3:ONOFF

它也是系统级的按键,用于长按进行开关机。

1.1.3 SW4

SW4是BOOT_MODE1脚,用来进行串行烧录模式切换,需要再与复位键配合使用。

本篇仅测试按键功能,因此可以该按键。

1.1.4 使用其中2个按键

板子上这4个按键的功能特性如下表:

本实验使用SW2和SW4这两个按键来进行实验。

2 软件编写

2.1 修改设备树文件

2.1.1 修改iomuxc节点

修改imx6ull-myboard.dts,在iomuxc节点的imx6ull-evk字节点下创建一个名为pinctrl_key的子节点,节点内容如下:

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文件中:

引脚宏定义后面的值,是对引脚功能的配置:

SW2:0x3080,即0011 0000 1000 0000

SW4:0xF080,即1000 0000 1000 0000

对照之前讲解GPIO的PAD寄存器的配置,根据两个按键的实际电路配置上拉或下拉。

/*
*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多行处,有:
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的按键节点,内容如下:

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配置为输入。

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实现数据的写入和读取。

/* 定义按键值 */
#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

按键的应用层程序,主要就通过驱动程序提供的按键读取接口,来循环读取按键的值,并在按键按下时,将按键的值打印出来。

/* 定义按键值 */
#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文件复制到启动文件夹:

网络方式启动开发板,查看key节点:

3.1.2 编译按键驱动程序

3.1.3 编译按键应用程序

3.2 测试

3.3 查看CPU占用率

先Ctrl+C结束掉此按键进程,然后使用如下指令来后台运行按键程序:

./key-App /dev/key &

然后再使用指令:

top

来查看CPU是使用情况。从下图可以看出,此时CPU的使用率是99.8%,全被按键检查程序占用了,因为按键程序中有个while循环在一直读取按键的值。

使用指令:

ps

查看按键的进程号,如下图为149,再使用:

kill -9 149

来杀掉按键进程,然后再使用top指令查看,可以看到CPU的使用率又变回了0。

实际的按键使用中,一般不会使用本篇的这种持续检测导致CPU占满的方式,本篇只是先来介绍GPIO的输入功能的使用,后续会使用更加高效的按键检测机制来实现按键检测功能。

4 总结

本篇主要介绍了i.MX6ULL的按键检测的使用,主要的知识点是设备树的修改,以及GPIO的输入配置与高低电平的读取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164756.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年java面试题之zookeeper基础2

一、请描述一下 Zookeeper 的通知机制是什么&#xff1f;Zookeeper 允许客户端向服务端的某个 znode 注册一个 Watcher 监听&#xff0c;当服务端的一些指定事件触发了这个 Watcher &#xff0c;服务端会向指定客户端发送一个事件通知来实现分布式的通知功能&#xff0c;然后客…

echarts基本用法

目录 tooltip:{ // 设置提示框信息 图表的提示框组件 legend:{ // 图例组件 toolbox : { //工具箱组件 可以另存为图片等功能 grid{ //网格配置 grid可以控制线型图 柱状图 图表大小 xAxs: { // 设置x轴的相关配置 y轴同理 series:[ // 系列图表 它决定着显示那种…

Spring MVC 详解 (Spring Boot)

Spring MVC 详解 - Spring Boot一、什么是 Spring MVC1.1 MVC 定义1.2 MVC 和 Spring MVC 的关系1.3 学习目的二、Spring MVC 创建和连接2.1 创建 Spring MVC 项目2.2 相关注解三、获取参数3.1 使用 Servlet API3.2 通过方法参数直接拿到3.2.1 传递单个参数3.2.2 传递多个参数3…

【Acwing 周赛复盘】第86场周赛复盘(2023.1.14)

【Acwing 周赛复盘】第86场周赛复盘 周赛复盘 ✍️ 本周个人排名&#xff1a;678/2358 AC情况&#xff1a;2/3 这是博主参加的第一次周赛&#xff0c;深刻体会到了世界的参差 &#x1f602; 看到排名 TOP3 的大佬都是不到 5 分钟内就 AK 了&#xff0c;真是恐怖如斯&#xff0…

29.动态内存申请

1.动态内存分配的概念 在数组一章中&#xff0c;介绍过数组的长度是预先定义好的&#xff0c;在整个程序中固定不变&#xff0c;但是在实际的编程中&#xff0c;往往所需的内存空间取决于实际输入的数据&#xff0c;而无法预先确定。为了解决上述问题&#xff0c;C语言提供了一…

Linux 发布 JavaWeb 项目

Linux 发布 JavaWeb 项目 安装 mysql 使用 yum search mysql-community 查看是否安装下载地址&#xff1a;https://dev.mysql.com/downloads/repo/yum/ 选择自己虚拟机的版本 在此处&#xff0c;复制 链接地址&#xff0c; 然后使用命令 wget 链接地址 来进行 下载rpm 安装 …

Python解题 - CSDN周赛第23期 - 树形背包与优化

以问哥目前的水平来看&#xff0c;本期的四道题的整体难度还是中等偏上的&#xff0c;而且从结果上来看&#xff0c; 也达到了竞赛的标准&#xff08;只有三名选手拿到满分&#xff09;。也许在某些大佬看来还是太简单了&#xff0c;毕竟都是模板题&#xff0c;直接套模板就能过…

基于深度学习人脸性别识别项目

项目概述要求针对提供的人脸数据集&#xff0c;根据人脸图像预测人脸性别。本次将提供 20000 多张已经分割的人脸图像&#xff0c;要求基于人脸图像自动识别该人性别。数据集的年龄从 1 岁覆盖到 100 多岁&#xff0c;包括了白种人、黄种人、黑种人等多种种族数据。数据集存在人…

2022年“网络安全”赛项海南省赛选拔赛 任务书

2022年“网络安全”赛项海南省赛选拔赛 任务书 一、竞赛时间 共计6小时。 &#xff08;二&#xff09;A模块基础设施设置/安全加固&#xff08;350分&#xff09; 一、项目和任务描述&#xff1a; 假定你是某企业的网络安全工程师&#xff0c;对于企业的服务器系统&#xff0c…

【数据结构】二叉搜索树

一、概念二叉搜索树也叫二叉排序树。在一颗二叉搜索树中&#xff0c;他的左子树二点节点值一定比根节点的值小&#xff0c;他的右子树节点的值一定比根节点的值大。二、特点他的左子树节点的值一定比根节点的值小他的右子树节点的值一定比根节点的值大他的每一颗子树都是一颗二…

java+springboot笔记2023002

java的注解机制&#xff1a; Java主要提供了5个基础注解&#xff0c;分别是&#xff1a; Override Deprecated SuppressWarnings SafeVarargs FunctionalInterface Java元注解&#xff1a; Retention&#xff0c; Target&#xff0c; Inherited&#xff0c; Documented&#x…

算法刷题打卡第66天:极大极小游戏

极大极小游戏 难度&#xff1a;简单 给你一个下标从 0 开始的整数数组 nums &#xff0c;其长度是 2 的幂。 对 nums 执行下述算法&#xff1a; 设 n 等于 nums 的长度&#xff0c;如果 n 1 &#xff0c;终止 算法过程。否则&#xff0c;创建 一个新的整数数组 newNums &a…

MySQL索引命中与失效

目录创建表MySQL执行优化器索引的命中与失效情况总结讨论MySQL索引命中与失效&#xff0c;我们得先来创建表 创建表 SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;-- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABL…

java动态规划算法

使用场景 动态规划最重要的是转移方程&#xff0c;而转移方程需要递归和记忆化搜索产生的表&#xff0c;因此直接贴出转移方程是没什么用的&#xff0c;不探究如何从递归到记忆化搜索再到转移方程&#xff0c;还是很难想到怎么去得到转移方程。下面我们将从例子中探寻如何三步走…

四、Gradle项目的生命周期

文章目录四、Gradle项目的生命周期【尚硅谷】Gradle教程-讲师&#xff1a;刘辉 生活明朗&#xff0c;万物可爱&#xff0c;人间值得&#xff0c;未来可期 四、Gradle项目的生命周期 Gradle 项目的生命周期分为三大阶段&#xff1a;Initialization -> Configuration -> E…

Maestro 薛定谔软件简单分子对接案例

##参考&#xff1a; Maestro 薛定谔软件使用&#xff1a; https://www.bilibili.com/video/BV1RN411X7Te https://www.youtube.com/watch?vNkM8jjHr7f4&listPL3dxdlKx_PcfuvHwJ0RjpZFt4HjwyTr7f Maestro 薛定谔对接&#xff1a; https://www.bilibili.com/video/BV17p…

【Java多线程】线程的常用方法

测试Thread中的常用方法1.start():启动当前线程&#xff1b;调用当前线程的run()2.run():通常需要重写Thread类中的此方法&#xff0c;将创建的线程要执行的3.currentThread():静态方法&#xff0c;返回当前代码的线程4.getName():获取当前线程的名字5.setName():设置当前线程的…

MySQL逻辑删除+Mybatis-Plus = 墙裂推荐

目录前言逻辑删除使用Mybatis-Plus逻辑删除它做了什么注意写在后面的一些话前言 一般情况下&#xff0c;我们要删除一条数据&#xff0c;直接使用 delete 即可&#xff0c;就像这样&#xff1a;delete from user where id 1&#xff0c;这样做的好处是&#xff1a; 符合我们…

C进阶_字符串库函数

目录 求字符串长度 strlen 常规实现 递归实现 指针-指针实现 长度不受限制的字符串函数 strcpy 模拟实现strcpy strcat 模拟实现strcat strcmp 模拟实现strcmp 长度受限制的字符串函数 strncpy strncat strncmp 求字符串长度 strlen size_t strlen ( const c…

前端工具(运用造型)

CSS预处理器的使用方法 1、什么是css预处理器 CSS预处理器是一种专门的编程语言&#xff0c;用来为CSS增加一些编程特性&#xff08;CSS本身不是编程语言&#xff09;不需要考虑浏览器兼容问题&#xff0c;因为CSS预处理器最终编译和输出的仍是标准的CSS样式。可以在CSS预处理…