Linux学习第20天:Linux按键输入驱动开发: 大道至简 量入为出

Linux版本号4.1.15   芯片I.MX6ULL                                    大叔学Linux    品人间百味  思文短情长 


        中国文化博大精深,太极八卦,阴阳交合,变化无穷。在程序的开发中也是这样,数字0和1也是同样的道理。就本节来说,输入和输出的万千变化才是程序驱动开发的基石。所以题目为大道至简,就是要说明这个道理。量入为出,不去纠结到底是先有输入还是先有输出。工作中接触最多的传感器就是输入,之后驱动开发根据采集到的输入进行判断比对后输出,也就是我要说的量入为出。

        本节开始学习第一个输入驱动的开发---按键驱动开发。主要内容包括按键驱动原理、硬件设计原理、驱动开发和测试。其中最重要的是驱动的开发和测试。

        本节的思维导图如下:

一、按键驱动原理

        在驱动程序中使用一个整形变量来表示按键值,应用程序通过 read 函数来读取按键值,判断按键有没有按下。保存按键值的变量就是个共享资源,驱动程序要向其写入按键值,应用程序要读取按键值。我们使用原子操作对这个按键值【整型数】进行赋值及读取。
 

二、硬件原理图

        按键 KEY0 是连接到 I.MX6U 的 UART1_CTS 这个 IO 上的, KEY0接了一个 10K 的上拉电阻,因此 KEY0 没有按下的时候 UART1_CTS 应该是高电平,当 KEY0按下以后 UART1_CTS 就是低电平。

三、驱动开发

1.修改设备树文件

1 #ifndef _BSP_GPIO_H
2 #define _BSP_GPIO_H
3 #define _BSP_KEY_H
4 #include "imx6ul.h"
5 /***************************************************************
6 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
7 文件名 : bsp_gpio.h
8 作者 : 左忠凯
9 版本 : V1.0
10 描述 : GPIO 操作文件头文件。
11 其他 : 无
12 论坛 : www.openedv.com
13 日志 : 初版 V1.0 2019/1/4 左忠凯创建
14 ***************************************************************/
15
16 /* 枚举类型和结构体定义 */
17 typedef enum _gpio_pin_direction
18 {
19 kGPIO_DigitalInput = 0U, /* 输入 */
20 kGPIO_DigitalOutput = 1U, /* 输出 */
21 } gpio_pin_direction_t;
22
23 /* GPIO 配置结构体 */
24 typedef struct _gpio_pin_config
25 {
26 gpio_pin_direction_t direction; /* GPIO 方向:输入还是输出 */
27 uint8_t outputLogic; /* 如果是输出的话,默认输出电平 */
28 } gpio_pin_config_t;

        枚举类型 gpio_pin_direction_t 表示 GPIO 方向,输入或输出。结构体 gpio_pin_config_t 是 GPIO 的配置结构体,里面有 GPIO 的方向和默认输出电平两个成员变量。

1 #include "bsp_gpio.h"
2 /***************************************************************
3 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
4 文件名 : bsp_gpio.h
5 作者 : 左忠凯
6 版本 : V1.0
7 描述 : GPIO 操作文件。
8 其他 : 无
9 论坛 : www.openedv.com
10 日志 : 初版 V1.0 2019/1/4 左忠凯创建
11 ***************************************************************/
12
13 /*
14 * @description : GPIO 初始化。
15 * @param - base : 要初始化的 GPIO 组。
16 * @param - pin : 要初始化 GPIO 在组内的编号。
17 * @param - config : GPIO 配置结构体。
18 * @return : 无
19 */
20 void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
21 {
22 if(config->direction == kGPIO_DigitalInput) /* 输入 */
23 {
24 base->GDIR &= ~( 1 << pin);
25 }
26 else /* 输出 */
27 {
28 base->GDIR |= 1 << pin;
29 gpio_pinwrite(base,pin, config->outputLogic);/* 默认输出电平 */
30 }
31 }
32
33 /*
34 * @description : 读取指定 GPIO 的电平值 。
35 * @param – base : 要读取的 GPIO 组。
36 * @param - pin : 要读取的 GPIO 脚号。
37 * @return : 无
38 */
39 int gpio_pinread(GPIO_Type *base, int pin)
40 {
41 return (((base->DR) >> pin) & 0x1);
42 }
43
44 /*
45 * @description : 指定 GPIO 输出高或者低电平 。
46 * @param – base : 要输出的的 GPIO 组。
47 * @param - pin : 要输出的 GPIO 脚号。
48 * @param – value : 要输出的电平, 1 输出高电平, 0 输出低低电平
49 * @return : 无
50 */
51 void gpio_pinwrite(GPIO_Type *base, int pin, int value)
52 {
53 if (value == 0U)
54 {
55 base->DR &= ~(1U << pin); /* 输出低电平 */
56 }
57 else
58 {
59 base->DR |= (1U << pin); /* 输出高电平 */
60 }
61 }

        函数 gpio_init 用于初始化指定的 GPIO 引脚,最终配置的是 GDIR 寄存器,此函数有三个参数,这三个参数的含义如下:
base: 要初始化的 GPIO 所属于的 GPIO 组,比如 GPIO1_IO18 就属于 GPIO1 组。
pin: 要初始化 GPIO 在组内的标号,比如 GPIO1_IO18 在组内的编号就是 18。
config: 要初始化的 GPIO 配置结构体,用来指定 GPIO 配置为输出还是输入。


        函数 gpio_pinread 是读取指定的 GPIO 值,也就是读取 DR 寄存器的指定位,此函数有两个
参数和一个返回值,参数含义如下:
base: 要读取的 GPIO 所属于的 GPIO 组,比如 GPIO1_IO18 就属于 GPIO1 组。
pin: 要读取的 GPIO 在组内的标号,比如 GPIO1_IO18 在组内的编号就是 18。
返回值: 读取到的 GPIO 值,为 0 或者 1。


        函数 gpio_pinwrite 是控制指定的 GPIO 引脚输入高电平(1)或者低电平(0),就是设置 DR 寄
存器的指定位,此函数有三个参数,参数含义如下:
base: 要设置的 GPIO 所属于的 GPIO 组,比如 GPIO1_IO18 就属于 GPIO1 组。
pin: 要设置的 GPIO 在组内的标号,比如 GPIO1_IO18 在组内的编号就是 18。
value: 要设置的值, 1(高电平)或者 0(低电平)。
        以后就可以使用函数 gpio_init 设置指定 GPIO 为输入还是输出,使用函数 gpio_pinread和 gpio_pinwrite 来读写指定的 GPIO。

2.按键驱动

15 /* 定义按键值 */
16 enum keyvalue{
17 KEY_NONE = 0,
18 KEY0_VALUE,
19 };

        bsp_key.h 文件中定义了一个枚举类型: keyvalue, 此枚举类型表示按键值。

1 #include "bsp_key.h"
2 #include "bsp_gpio.h"
3 #include "bsp_delay.h"
4 /***************************************************************
5 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
6 文件名 : bsp_key.c
7 作者 : 左忠凯
8 版本 : V1.0
9 描述 : 按键驱动文件。
10 其他 : 无
11 论坛 : www.openedv.com
12 日志 : 初版 V1.0 2019/1/4 左忠凯创建
13 ***************************************************************/
14
15 /*
16 * @description : 初始化按键
17 * @param : 无
18 * @return : 无
19 */
20 void key_init(void)
21 {
22 gpio_pin_config_t key_config;
23
24 /* 1、初始化 IO 复用, 复用为 GPIO1_IO18 */
25 IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);
26
27 /* 2、、配置 UART1_CTS_B 的 IO 属性
28 *bit 16:0 HYS 关闭
29 *bit [15:14]: 11 默认 22K 上拉
30 *bit [13]: 1 pull 功能
31 *bit [12]: 1 pull/keeper 使能
32 *bit [11]: 0 关闭开路输出
33 *bit [7:6]: 10 速度 100Mhz
34 *bit [5:3]: 000 关闭输出
35 *bit [0]: 0 低转换率
36 */
37 IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0xF080);
38
39 /* 3、初始化 GPIO GPIO1_IO18 设置为输入*/
40 key_config.direction = kGPIO_DigitalInput;
41 gpio_init(GPIO1,18, &key_config);
42
43 }
44
45 /*
46 * @description : 获取按键值
47 * @param : 无
48 * @return : 0 没有按键按下,其他值:对应的按键值
49 */
50 int key_getvalue(void)
51 {
52 int ret = 0;
53 static unsigned char release = 1; /* 按键松开 */
54
55 if((release==1)&&(gpio_pinread(GPIO1, 18) == 0)) /* KEY0 按下 */
56 {
57 delay(10); /* 延时消抖 */
58 release = 0; /* 标记按键按下 */
59 if(gpio_pinread(GPIO1, 18) == 0)
60 ret = KEY0_VALUE;
61 }
62 else if(gpio_pinread(GPIO1, 18) == 1) /* KEY0 未按下 */
63 {
64 ret = 0;
65 release = 1; /* 标记按键释放 */
66 }
67
68 return ret;
69 }

        bsp_key.c 中一共有两个函数: key_init key_getvalue, key_init 是按键初始化函数,用来初始化按键所使用的 UART1_CTS 这个 IO。

        函数 key_init 先设置 UART1_CTS 复用为GPIO1_IO18,然后配置 UART1_CTS 这个 IO 为速度为 100MHz,默认 22K 上拉。最后调用函数 gpio_init 来设置 GPIO1_IO18 为输入功能。
        函数 key_getvalue 用于获取按键值,此函数没有参数,只有一个返回值,返回值表示按键
值,返回值为 0 的话就表示没有按键按下,如果返回其他值的话就表示对应的按键按下了。获
取按键值其实就是不断的读取 GPIO1_IO18 的值,如果按键按下的话相应的 IO 被拉低,那么
GPIO1_IO18 值就为 0,如果按键未按下的话 GPIO1_IO18 的值就为 1。此函数中静态局部变量
release 表示按键是否释放。

       第57 行是按键消抖延时函数,这个很多地方都有讲的,很简单,就不赘述了。

1 #include "bsp_clk.h"
2 #include "bsp_delay.h"
3 #include "bsp_led.h"
4 #include "bsp_beep.h"
5 #include "bsp_key.h"
6
7 /*
8 * @description : main 函数
9 * @param : 无
10 * @return : 无
11 */
12 int main(void)
13 {
14 int i = 0;
15 int keyvalue = 0;
16 unsigned char led_state = OFF;
17 unsigned char beep_state = OFF;
18
19 clk_enable(); /* 使能所有的时钟 */
20 led_init(); /* 初始化 led */
21 beep_init(); /* 初始化 beep */
22 key_init(); /* 初始化 key */
23
24 while(1)
25 {
26 keyvalue = key_getvalue();
27 if(keyvalue)
28 {
29 switch (keyvalue)
30 {
31 case KEY0_VALUE:
32 beep_state = !beep_state;
33 beep_switch(beep_state);
34 break;
35 }
36 }
37 i++;
38 if(i==50)
39 {
40 i = 0;
41 led_state = !led_state;
42 led_switch(LED0, led_state);
43 }
44 delay(10);
45 }
46 return 0;
47 }

        main.c 函数先初始化 led 灯、蜂鸣器和按键,然后在 while(1)循环中不断的调用函数
key_getvalue 来读取按键值,如果 KEY0 按下的话就打开/关闭蜂鸣器。 LED0 作为系统提示指
示灯闪烁,闪烁周期大约为 500ms。

四、测试

        前面几节课中的通用 Makefile,修改变量 TARGET 为 key,在变量 INCDIRS和 SRCDIRS 中追加“ bsp/gpio” 和“ bsp/key”。

1 CROSS_COMPILE ?= arm-linux-gnueabihf-
2 TARGET ?= key
3
4 /* 省略掉其它代码...... */
5
6 INCDIRS := imx6ul \
7 bsp/clk \
8 bsp/led \
9 bsp/delay \
10 bsp/beep \
11 bsp/gpio \
12 bsp/key
13
14 SRCDIRS := project \
15 bsp/clk \
16 bsp/led \
17 bsp/delay \
18 bsp/beep \
19 bsp/gpio \
20 bsp/key
21
22 /* 省略掉其它代码...... */
23
24 clean:
25 rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

第 2 行修改变量 TARGET 为“ key”,也就是目标名称为“ key”。
第 11、 12 行在变量 INCDIRS 中添加 GPIO 和按键驱动头文件(.h)路径。
第 19、 20 行在变量 SRCDIRS 中添加 GPIO 和按键驱动文件(.c)路径。

        使用 Make 命令编译代码,编译成功以后使用软件 imxdownload 将编译完成的 key.bin 文件
下载到 SD 卡中,命令如下:
chmod 777 imxdownload //给予 imxdownload 可执行权限,一次即可
./imxdownload key.bin /dev/sdd //烧写到 SD 卡中
        烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板。如果代码运行正常的
话 LED0 会以大约 500ms 周期闪烁, 按下开发板上的 KEY0 按键,蜂鸣器打开,再按下 KEY0
按键,蜂鸣器关闭。

五、总结

        这一节是非常重要的一个内容,作为驱动开发基石的输入和输出一定要学会记牢。主要内容包括按键驱动原理、硬件设计原理、驱动开发和测试。其中最重要的是驱动的开发和测试。

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

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

相关文章

【Pm4py第七讲】关于visualization

本节用于介绍pm4py中的可视化函数&#xff0c;包括可视化bpmn、petri、性能图谱、变迁系统等。 1.函数概述 本次主要介绍Pm4py中一些常见的可视化函数&#xff0c;总览如下表&#xff1a; 函数名说明view_alignments(log, aligned_traces[, format])可视化对齐方法 view_bpmn(…

华为云云耀云服务器L实例评测 | 云服务器搭建自己的gitlab代码仓库手把手教学

&#x1f4cb; 前言 &#x1f5b1; 博客主页&#xff1a;在下马农的碎碎念&#x1f917; 欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd;✍ 本文由在下马农原创&#xff0c;首发于CSDN&#x1f4c6; 首发时间&#xff1a;2023/09/26&#x1f4c5; 最近更新时…

【LeetCode热题100】--234.回文链表

234.回文链表 快慢指针&#xff1a; 将链表的后半部分反转&#xff08;改变链表结构&#xff09;&#xff0c;然后将前半部分和后半部分进行比较。比较完成后我们应该将链表恢复原样。虽然不需要恢复也能通过测试用例 使用快慢指针在一次遍历中找到链表的中间位置&#xff1a…

Spring整合RabbitMQ——消费者

1.配置consumer xml配置文件 2. 实现MessageListener接口 并重写onMessage方法

GPT4科研实践技术与AI绘图

GPT对于每个科研人员已经成为不可或缺的辅助工具&#xff0c;不同的研究领域和项目具有不同的需求。如在科研编程、绘图领域&#xff1a;1、编程建议和示例代码: 无论你使用的编程语言是Python、R、MATLAB还是其他语言&#xff0c;都可以为你提供相关的代码示例。2、数据可视化…

Mysql高级——数据库设计规范(2)

8. ER模型 ER 模型中有三个要素&#xff0c;分别是实体、属性和关系。 实体&#xff0c;可以看做是数据对象&#xff0c;往往对应于现实生活中的真实存在的个体。在 ER 模型中&#xff0c;用矩形来表示。实体分为两类&#xff0c;分别是强实体和弱实体。强实体是指不依赖于其…

ACP值不值得考?考了有用吗?

ACP是什么&#xff1f; PMI-ACP是由美国项目管理协会PMI颁发的针对敏捷项目管理的专业认证。目前已覆盖全球206个国家和地区&#xff0c;为计算机IT、制造、医疗保健等各行各业的项目成果交付提供了一系列方法和实践&#xff0c;是国际上敏捷领域中知识方法最全面、含金量最高…

OpenAI 更新 ChatGPT:支持图片和语音输入【附点评】

一、消息正文 9月25日消息,近日OpenAI宣布其对话AI系统ChatGPT进行升级,添加了语音输入和图像处理两个新功能。据OpenAI透露,这些新功能将在未来两周内面向ChatGPT Plus付费用户推出,免费用户也将很快可以使用这些新功能。这标志着ChatGPT继续朝着多模态交互的方向发展,为用户提…

液氮超低温保存法的原理

细菌保存是有效保存活体微生物群体&#xff0c;使细菌不死、不衰、不变&#xff0c;便于研究和应用。保存细菌的方法有很多。保存原理是利用干燥、低温、隔离空气的方法&#xff0c;降低微生物菌株的代谢速度&#xff0c;使菌株的生命活动处于半永久性休眠状态&#xff0c;从而…

CentOS下安装MySQL 8.1及备份配置

1 卸载原来的MySQL版本 移除之前部署的mysql软链接 # unlink /etc/init.d/mysql # unlink /usr/bin/mysql2 下载最新的MySQL版本 https://dev.mysql.com/downloads/mysql/8.0.html 我这里直接把地址放在这里&#xff1a;https://cdn.mysql.com//Downloads/MySQL-8.1/mysql…

Windows10操作系统部署AD

windows 10 安装配置AD 一、启用AD 1.打开控制面板—>程序—>启用或关闭windows功能 2.勾选Active Directory Lightweight Directory Services&#xff08;Active Directory 轻型目录服务&#xff09; 注&#xff1a;不同版本中英文显示有区别&#xff0c;认准AD字样就…

leetcodetop100 (22) 反转链表

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表 简单的用一个动态数组Arraylist记录&#xff0c;然后倒序遍历赋值给一个新的链表&#xff0c;这种空间复杂度是o(n),估计需要优化。 采用双指针&#xff1b; 我们可以申请两个指针&#xf…

机器人中的数值优化|【四】L-BFGS理论推导与延伸

机器人中的数值优化|【四】L-BFGS理论推导与延伸 往期内容回顾 机器人中的数值优化|【一】数值优化基础 机器人中的数值优化|【二】最速下降法&#xff0c;可行牛顿法的python实现&#xff0c;以Rosenbrock function为例 机器人中的数值优化|【三】无约束优化&#xff0c;拟牛…

汽车电子——产品标准规范汇总和梳理(自动驾驶)

文章目录 前言 一、分级 二、定位 三、地图 四、座舱 五、远程 六、信息数据 七、场景 八、智慧城市 九、方法论 总结 前言 见《汽车电子——产品标准规范汇总和梳理》 一、分级 《GB/T 40429-2021 汽车驾驶自动化分级》 《QC/T XXXXX—XXXX 智能网联汽车 自动驾…

位图布隆过滤器

文章目录 位图&布隆过滤器1. 位图1.1位图概念1.2位图原理1.3位图实现1.4位图排序 2. 布隆过滤器2.1 引入布隆过滤器2.2 概念2.3 布隆过滤器插入2.4 布隆过滤器的查找2.5 布隆过滤器模拟实现2.6 布隆过滤器的删除2.7 布隆过滤器优缺点2.8 布隆过滤器使用场景 3. 海量数据问题…

浙江移动与中兴通讯合作项目被评为“光华杯”东部赛区一等奖!

近日&#xff0c;浙江移动携手中兴通讯共同打造的创新合作项目“构建面向东数西算的传输全光底座赋能美丽浙江”在2023年第二届“光华杯”东部赛区决赛中被评为一等奖&#xff0c;该项目以运力为核心&#xff0c;可实践应用于“东数西算”建设工程当中&#xff0c;提供高速无阻…

interview6-jvm篇

JVM(Java Virtual Machine)Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09; 在JVM中共有四大部分&#xff0c;分别是ClassLoader&#xff08;类加载器&#xff09;、Runtime DataArea&#xff08;运行时数据区&#xff0c;内存分区&#xff09;、Execu…

探索创意的新辅助,AI与作家的完美合作

在现代社会&#xff0c;文学创作一直是人类精神活动中的重要一环。从古典文学到现代小说&#xff0c;从诗歌到戏剧&#xff0c;作家们以他们的独特视角和文学天赋为我们展示了丰富多彩的人生世界。而近年来&#xff0c;人工智能技术的快速发展已经渗透到各行各业&#xff0c;文…

JavaWeb 学习

1. 基本概念 1.1 Web web&#xff1a;网络&#xff0c;网页 静态 web html&#xff0c;css提供给所有人看的数据始终不会变化 动态 web 淘宝提供给每个人看的数据会有所不同技术栈&#xff1a;Servlet/JSP&#xff0c;ASP&#xff0c;PHP Java 中&#xff0c;动态 web 资…

【神印王座】悲啸洞穴之物揭晓,圣采儿差点被骗,幸好龙皓晨聪明

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析神印王座。 神印王座动漫现阶段已经出到龙皓晨等人接取新任务深入魔族地界的阶段&#xff0c;而龙皓晨等人接取的任务想必现在大家都知道了&#xff0c;那就是探索魔族地界中的悲啸洞穴。但是大家知道悲啸洞穴里面藏着什么…