ARM(IMX6U)裸机按键输入实验(BSP+SDK、GPIO输入与输出、按键消抖)

参考:Linux之ARM(IMX6U)裸机按键输入实验(GPIO的输出与输入)
作者:一只青木呀
发布时间: 2020-08-17 21:43:37
网址:https://blog.csdn.net/weixin_45309916/article/details/108057687

目录

  • 1、按键输入简介
  • 2、硬件原理图分析
    • 原理图
    • 配置寄存器为GPIO
    • 配置寄存器的电器属性
  • 3、实验程序的编写
    • 3.1、bsp_gpio.h
    • 3.2、bsp_gpio.c
    • 3.3、gpio_key.h
    • 3.4、gpio_key.c(按键消抖delay完再读取状态值)
    • 3.5、main.c
  • 4、编译下载验证
    • 4.1、连接脚本的编写
    • 4.2、Makefile的编写
    • 4.3、编译下载
  • 出现的问题(清除BSS段代码4字节对齐)

前面几篇文章试验都是讲解如何使用 I.MX6U 的 GPIO 输出控制功能, I.MX6U 的 IO 不仅能作为输出,而且也可以作为输入I.MX6U-ALPHA 开发板上有一个按键,按键连接了一个 IO,将这个 IO 配置为输入功能,读取这个 IO 的值即可获取按键的状态(按下或松开)。本篇文章通过这个按键来控制蜂鸣器的开关

1、按键输入简介

按键就两个状态:按下或弹起,将按键连接到一个 IO 上,通过读取这个 IO 的值就知道按键是按下的还是弹起的。至于按键按下的时候是高电平还是低电平要根据实际电路来判断。

I.MX6U-ALPHA 开发板上有一个按键 KEY0,本篇文章我们将会编写代码通过这个 KEY0 按键来控制开发板上的蜂鸣器,按一下 KEY0 蜂鸣器打开,再按一下蜂鸣器就关闭

2、硬件原理图分析

本试验我们用到的硬件有:

1) LED 灯 LED0。
2)蜂鸣器。
3) 1 个按键 KEY0。

原理图

按键 KEY0 的原理图如图 15.2.1 所示:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
从图可以看出,按键 KEY0 是连接到 I.MX6U 的 UART1_CTS 这个 IO 上的, KEY0接了一个 10K 的上拉电阻,因此KEY0 没有按下的时候 UART1_CTS 应该是高电平,当 KEY0按下以后 UART1_CTS 就是低电平,采用轮询方式检测。

配置寄存器为GPIO

在这里插入图片描述

在这里插入图片描述

配置寄存器的电器属性

在这里插入图片描述
在这里插入图片描述

描述
bit 160 HYS 关闭
bit [15:14]11 默认 22K 上拉
bit [13]1 pull 功能
bit [12]1 pull/keeper 使能
bit [11]0 关闭开路输出
bit [7:6]10 速度 100Mhz
bit [5:3]000 关闭输出
bit [0]0 低转换率

3、实验程序的编写

本次实在在上一次实验的基础上完成(蜂鸣器实验),我们把上一篇的代码复制一份,在上面做修改,重新创建 VSCode 工程,工作区名字为“key”,在工程目录的 bsp 文件夹中创建名为“key”和“gpio”两个文件夹。按键相关的驱动文件都放到“key”文件夹中,本次试验我们对 GPIO 的操作编写一个函数集合,也就是编写一个 GPIO驱动文件, GPIO 的驱动文件放到“gpio”文件夹里面。

新建 bsp_gpio.c 和 bsp_gpio.h 这两个文件,将这两个文件都保存到刚刚创建的 bsp/gpio 文件夹里面

3.1、bsp_gpio.h

#ifndef __BSP_KEY_H
#define __BSP_KEY_H#include "imx6ul.h"typedef enum _gpio_pin_direction {//枚举类型kGPIO_DigitalInput = 0U,  /*输入*/kGPIO_DigitalOutput = 1U,  /*输出*/}gpio_pin_direction_t;typedef struct _gpio_pin_config {gpio_pin_direction_t direction;  /*gpio方向:输入还是输出*/uint8_t  outputLogic;  /*如果是输出的话,默认输出低电平*/}gpio_pin_config_t;void gpio_init(GPIO_Type *base,int pin, gpio_pin_config_t *config);
int gpio_pinread(GPIO_Type *base,int pin);
void gpio_pinwrite(GPIO_Type *base,int pin,int value);#endif // !__BSP_KEY_H

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

3.2、bsp_gpio.c

#include "bsp_gpio.h"/** @description : GPIO 初始化。* @param - base : 要初始化的 GPIO 组。* @param - pin : 要初始化 GPIO 在组内的编号。* @param - config : GPIO 配置结构体。* @return : 无*/void gpio_init(GPIO_Type *base,int pin, gpio_pin_config_t *config)
{if(config->direction == kGPIO_DigitalInput)  /*输入*/{base->GDIR &= ~(1 << pin);}else  /*输出*/{base->GDIR |= (1 << pin);gpio_pinwrite(&base,pin,config->outputLogic); /*默认输出电平*/}}/** @description : 读取指定 GPIO 的电平值 。* @param – base : 要读取的 GPIO 组。* @param - pin : 要读取的 GPIO 脚号。* @return : 无*/int gpio_pinread(GPIO_Type *base,int pin)
{return (((base->DR) >> pin) & 0x1);
}/** @description : 指定 GPIO 输出高或者低电平 。* @param – base : 要输出的的 GPIO 组。* @param - pin : 要输出的 GPIO 脚号。* * @param – value : 要输出的电平, 1 输出高电平, 0 输出低低电平* @return : 无*/void gpio_pinwrite(GPIO_Type *base,int pin,int value)
{if(value == 0U){base->DR &= ~(1U<<pin);  /*输出低电平*/}else{base->DR |= (1U << pin);  /*输出高电平*/}}

文件 bsp_gpio.c 中有三个函数: gpio_init、 gpio_pinread 和 gpio_pinwrite,函数 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

接下来编写按键驱动文件,新建 bsp_key.c 和 bsp_key.h 这两个文件,将这两个文件都保存到刚刚创建的 bsp/key 文件夹里面

3.3、gpio_key.h

#ifndef __BSP_KEY_H
#define __BSP_KEY_H#include "imx6ul.h"
#include "bsp_delay.h"/*定义按键值  枚举 方便有多个按键 这里只有一个按键*/
enum keyvalue {KEY_NONE =0,KEY_VALUE ,
};/*函数声明*/
void key_init();
int key_get_value();#endif // !__BSP_KEY_H

bsp_key.h 文件中定义了一个枚举类型: keyvalue, 此枚举类型表示按键值, 因为 I.MX6UALPHA 开发板上只有一个按键,因此枚举类型里面只到 KEY0_VALUE

3.4、gpio_key.c(按键消抖delay完再读取状态值)

#include "bsp_key.h"/** @description : 初始化按键* @param : 无* @return : 无*/void key_init(void)
{gpio_pin_config_t key_config;/* 1、初始化 IO 复用, 复用为 GPIO1_IO18  .h文件找到这个宏*/IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18, 0);/* 2、、配置 UART1_CTS_B 的 IO 属性*bit 16:0 HYS 关闭*bit [15:14]: 11 默认 22K 上拉*bit [13]: 1 pull 功能*bit [12]: 1 pull/keeper 使能*bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度 100Mhz*bit [5:3]: 000 关闭输出*bit [0]: 0 低转换率*/                                              //0xf080演算过程如下图所示IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xf080);/* 3、初始化 GPIO GPIO1_IO18 设置为输入*/key_config.direction=kGPIO_DigitalInput;gpio_init(GPIO1,18,&key_config);//或者不用库函数 直接操作结构体里的寄存器://GPIO1->GDIR &= ~(1<<18);}/*
* @description : 获取按键值
* @param : 无
* @return : 0 没有按键按下,其他值:对应的按键值
*/
int key_get_value(void)
{int ret =0;static unsigned char release =1; /*为1表示按键处于释放状态*/if((release == 1) &&  (gpio_pin_read(GPIO1,18) == 0))//释放状态下检测到按键被按下{delay(10);  /*按键消抖处理 大概10ms就够了*/release = 0;if(gpio_pin_read(GPIO1,18) == 0)//延时10ms读取还是0 说明按键按下是有效的{ret = KEY_VALUE;}}else if(gpio_pin_read(GPIO1,18) == 1)//没有被按下{ret =0;release = 1;}return ret;
}

程序中2、配置 UART1_CTS_B 的 IO 属性的演算过程:这里是引用
按键消抖原理:
在这里插入图片描述

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 表示按键是否释放。

3.5、main.c


#include "main.h"int main() 
{int i=0;int keyvalue=0;   unsigned char led_status= OFF;unsigned char beep_status= OFF;clk_enable(); //使能外设时钟led_init(); //初始化LEDinit_beep();//初始化蜂鸣器key_init(); //初始化keywhile(1){//按键控制蜂鸣器keyvalue = key_getvalue();if(keyvalue)//值为正 表示有效的按键值{switch (keyvalue)//按键状态{case KEY_VALUE://这里只写了一种casebeep_status=!beep_status;beep_switch(beep_status);break;default:break;}}i++;if(i==50)//50*10=500ms  灯亮灭一次{i=0;led_status=!led_status;led_switch(LED0,led_status);}}return 0;
}

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

4、编译下载验证

4.1、连接脚本的编写

SECTIONS
{. = 0x87800000;.text :{obj/start.o*(.text)}.rodata ALIGN(4) : {*(.rodata*)}.data ALIGN(4) : {*(.data)}. = ALIGN(4) ;__bss_start = .;.bss ALIGN(4) : { *(.bss) *(COMMON)}__bss_end = .;
}

这里注意bss段需要四字节对其,否则会清除其他字段的内容,造成程序的崩溃

4.2、Makefile的编写

CROSS_COMPILE 	?= arm-linux-gnueabihf-
TARGET		  	?= keyCC 				:= $(CROSS_COMPILE)gcc
LD				:= $(CROSS_COMPILE)ld
OBJCOPY 		:= $(CROSS_COMPILE)objcopy
OBJDUMP 		:= $(CROSS_COMPILE)objdumpINCDIRS 		:= imx6ul \bsp/clk \bsp/led \bsp/delay \bsp/beep \bsp/gpio \bsp/keySRCDIRS			:= project \bsp/clk \bsp/led \bsp/delay \bsp/beep \bsp/key \bsp/gpio INCLUDE			:= $(patsubst %, -I %, $(INCDIRS))SFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.s))
CFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))SFILENDIR		:= $(notdir  $(SFILES))
CFILENDIR		:= $(notdir  $(CFILES))SOBJS			:= $(patsubst %, obj/%, $(SFILENDIR:.s=.o))
COBJS			:= $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS			:= $(SOBJS) $(COBJS)VPATH			:= $(SRCDIRS).PHONY: clean$(TARGET).bin : $(OBJS)$(LD) -Timx6ul.lds -o $(TARGET).elf $^$(OBJCOPY) -O binary -S $(TARGET).elf $@$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis$(SOBJS) : obj/%.o : %.s$(CC) -Wall -nostdlib -c -O2  $(INCLUDE) -o $@ $<$(COBJS) : obj/%.o : %.c$(CC) -Wall -nostdlib -c -O2  $(INCLUDE) -o $@ $<clean:rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)	

4.3、编译下载

使用 Make 命令编译代码,编译成功以后使用软件 imxdownload 将编译完成的 key.bin 文件下载到 SD 卡中,命令如下:

chmod 777 imxdownload              //给予 imxdownload 可执行权限,一次即可
./imxdownload key.bin  /dev/sdd    //烧写到 SD 卡中

烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板。如果代码运行正常的话 LED0 会以大约 500ms 周期闪烁, 按下开发板上的 KEY0 按键,蜂鸣器打开,再按下 KEY0按键,蜂鸣器关闭

具体烧写过程请参考程序烧写到SD卡详情

出现的问题(清除BSS段代码4字节对齐)

在这里插入图片描述

解决方法:

在这里插入图片描述
编译再次查看反汇编文件中BSS段的地址

按照四字节对齐原则,发现往后移动了,能被4整除
在这里插入图片描述

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

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

相关文章

php 提取正文算法,PHP生成文章摘要算法_栈

之前网上复制了一个摘要算法&#xff0c;一直使用正常。最近写的一篇前500字里含有超链接&#xff0c;就导致摘要生成有误&#xff0c;从而影响了前端样式。所以后面打算自己写&#xff0c;想起大学编译原理匹配表达式的大致思想&#xff0c;就决定采用栈的思想试试。实现目标&…

设计模式 之 《组合模式》

GOOD&#xff1a;整体和部分可以被一致对待&#xff08;如WORD中复制一个文字、一段文字、一篇文章都是一样的操作&#xff09; #ifndef __COMPOSITE_MODEL__ #define __COMPOSITE_MODEL__ #include <iostream> #include <string> #include <vector> using n…

ARM(IMX6U)裸机主频和时钟

参考&#xff1a;Linux之ARM&#xff08;IMX6U&#xff09;裸机主频和时钟配置 作者&#xff1a;一只青木呀 发布时间&#xff1a; 2020-08-28 10:39:17 网址&#xff1a;https://blog.csdn.net/weixin_45309916/article/details/108237599 目录1、I.MX6U 时钟系统详解系统时钟…

关联矩阵古林法的matlab代码,[转载][原创]灰色关联分析及Matlab程序实现

灰色系统理论由我国著名学者邓聚龙教授于1982提出。灰色关联分析是灰色系统理论的一个分支&#xff0c;应用灰色关联分析方法对受多种因素影响的事物和现象从整体观念出发进行综合评价是一个被广为接受的方法。一、灰色关联分析法的建模过程灰色关联分析法的基本思想是根据各比…

C语言排序(桶排序,冒泡排序,选择排序,插入排序,快速排序)

参考&#xff1a;C语言五大排序&#xff08;桶排序&#xff0c;冒泡排序&#xff0c;选择排序&#xff0c;插入排序&#xff0c;快速排序&#xff09;动态演示 作者&#xff1a;一只青木呀 发布时间&#xff1a; 2020-09-09 20:18:43 网址&#xff1a;https://blog.csdn.net/we…

FIFO分枝_限界算法

问题&#xff1a; 检索4-皇后问题的状态空间树如下图的基本过程。&#xff08;4-皇后问题解空间的树结构&#xff0c;结点按深度优先检索编号&#xff09; 如果按序扩展这些结点&#xff0c;则下一个E-结点就是结点2。扩展结点2后生成结点3&#xff0c;8和13。利用限界函数(同行…

智能家居APP使用指南

参考&#xff1a;智能家居APP使用指南 作者&#xff1a;图触靓 发布时间&#xff1a; 2021-04-14 14:11:40 网址&#xff1a;https://blog.csdn.net/bhbhhyg/article/details/115694774 目录一、如何修改IP&#xff0c;端口号&#xff0c;以及发送的指令二、如何增加或者删除一…

python zlib字符串压缩

2019独角兽企业重金招聘Python工程师标准>>> 在做网络程序时,可以对字符串进行压缩来节省带宽 项目中用到 {"compress": <压缩标记>, "result":[[设备类型.设备ID, 设备名称, 单位ID, 设备功能], ...]} 只做了简单的压缩解压缩,也没crc3…

linux做一个客户端与WemosD1作为服务器的无线通信(局域网通信)

参考&#xff1a;linux做一个客户端与WemosD1作为服务器的无线通信&#xff08;局域网通信&#xff09; 作者&#xff1a;枕上 发布时间&#xff1a;2021-07-19 23:33:44 网址&#xff1a;https://blog.csdn.net/jinchi_boke/article/details/118916896?utm_sourceapp&app…

C语言学习书籍推荐《C语言程序设计 现代方法(第2版)》下载

下载地址&#xff1a;点我 C语言仍然是计算机领域的通用语言之一&#xff0c;但现在的C语言已经和当初的时候大不相同了。本书主要的一个目的就是通过一种“现代方法”来介绍C语言&#xff0c;书中强调标准C&#xff0c;强调软件工程&#xff0c;不再强调“手工优化”。这一版中…

wemosD1_WIFI模块 与 arduino

参考&#xff1a;wemosD1_WIFI模块 与 arduino 作者&#xff1a;枕上 发布时间&#xff1a;2021-07-19 21:49:55 网址&#xff1a;https://blog.csdn.net/jinchi_boke/article/details/118915142 目录作为设备接入wifi&#xff08;STA模式&#xff09;架设Wemos为ftp服务器ardu…

本机在合成图片经常提示内存不足

转载于:https://www.cnblogs.com/niyl/p/9988614.html

tp5 php7 报500,记一次TP单元测试报500错误的问题

记一次TP单元测试报500错误的问题一直听说好的单元测试能提高代码质量&#xff0c;昨天终于在下定决心弄懂单元测试&#xff0c;但第一步就把我干趴下了&#xff0c;我的问题在下面开始都没有什么问题&#xff0c;tp5单元测试的手册就那一点&#xff0c;通过看云上一位仁兄写的…

H3C配置

H3C交换机配置 1.查看设备版本,确定是否需要升级 <H3C>dis version 2.vlan及接口配置 注&#xff1a;正式配置前可以查看下现有的VLAN。命令如下 <H3C>dis vlan <H3C>sys                          //进入系统视图模式 [H3C]vlan …

创建自己的共用js库

直至昨晚为止&#xff0c;学习了一个多月的MVC与jQuery&#xff0c;从所做的练习中&#xff0c;发觉jQuery的代码也有跟C#语言一样可以重构&#xff0c;多页面有相同使用的方法函数&#xff0c;均可以放置于一个单独立的js文件或是自定义的js库中。在使用时&#xff0c;引用此库…

视频专辑:JAVA语言入门视频教程

为什么80%的码农都做不了架构师&#xff1f;>>> 专辑&#xff1a;JAVA语言入门视频教程 简介:该视频专辑是java的入门教程&#xff0c;适合初学者学习java&#xff0c;讲的也非常容易懂&#xff0c;希望能给想学习java的朋友一些帮助。 1 JAVASE 01 简介 2013-10…

视频专辑:Servlet视频教程

为什么80%的码农都做不了架构师&#xff1f;>>> 专辑&#xff1a;Servlet视频教程 简介:郭宏志 Servlet视频教程 1 郭宏志 Servlet 01 WEB工程结构 2013-10-26 00:32 | 播放(9) | 评论(0) | 时长:28:39 2 郭宏志 Servlet 02 Servlet简介 2013-10-26 00:31 …

基于wemos D1的无线遥控灯(433m无线模块)

参考&#xff1a;基于wemos D1的无线遥控灯(433m无线模块) 作者&#xff1a;一只小阿大:) 发布时间&#xff1a; 2021-04-16 09:25:53 网址&#xff1a;https://blog.csdn.net/qq_44610809/article/details/115747714 项目软硬件平台及开发环境 1.硬件平台 开发板&#xff1a…

Linux实战教学笔记37:企业级Nginx Web服务优化实战(上)

一&#xff0c;Nginx基本安全优化 1.1 调整参数隐藏Nginx软件版本号信息 一般来说&#xff0c;软件的漏洞都和版本有关&#xff0c;这个很像汽车的缺陷&#xff0c;同一批次的要有问题就都有问题&#xff0c;别的批次可能就都是好的。因此&#xff0c;我们应尽量隐藏或消除Web服…

探索云计算、大数据的特色化应用之路

云计算与大数据是当前最热门的两个话题&#xff0c;除了技术上的相关性以外&#xff0c;两者现在都面临同一个问题&#xff0c;就是如何更快更好地落地&#xff0c;也就是将云计算、大数据所代表的新技术、新业务模式与行业用户的实际需求紧密结合起来&#xff0c;驱动企业业务…