STM32第七节:GPIO输入——按键检测(包含带参宏)

目录

前言

STM32第七节:GPIO输入——按键检测(包含带参宏)

带参宏

代码替换展示

定义带参宏

GPIO输入——按键检测

硬件部分

端口输入数据寄存器(GPIOx_IDR)

编写程序

配置以及编写bsp_key文件

main函数编程

bsp_led.c以及bsp_led.h文件函数编程

使用固件库控制io口

直接操作寄存器的方法控制IO

小结


前言

        上节课我们学习了GPIO输出——使用固件库点亮LED,包含LED以及GPIO的讲解,以及具体代码的编写。那么我们节本课就接着上节课讲讲带参宏以及GPIO输入——按键检测。

        创作不易,点个三连霸!


STM32第七节:GPIO输入——按键检测(包含带参宏)

带参宏

代码替换展示

        我们在编写程序的时候,在其他代码里见到过带参宏的定义;例如LED_G(ON/OFF);这种定义,那么带参宏是纯粹的C语言知识,我们看以下的代码,这里就在上一节的基础上相当于替换掉了GPIO口操作的两行代码,换成了带参宏。

	//GPIO_SetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);LED_G(OFF);Delay(0xFFFFF);//GPIO_ResetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);LED_G(ON);Delay(0xFFFFF);

        那么,我们该如何定义带参宏呢?

定义带参宏

        那么我们打开bsp_led.h,再次定义两个宏ON/OFF:

#define ON     1
#define OFF    0#define LED_G(a)  if(a) \GPIO_ResetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);\else  GPIO_SetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);

        这里我们其实是写了一个宏定义函数,我们设置了ON为1,OFF为0;在下面的宏函数中,定义LED_G(a)中的参量是否为1或0;这样我们就可以控制输出的具体代码,使得main.c文件更加简洁明了,可读性更强。

GPIO输入——按键检测

        上节课讲了GPIO口的输出,这节课我们来讲讲输入。我们可以通过一个按键,来改变外部的这个电平的状态,让io口来读取电平的状态。

硬件部分

        在我们的指南者板子上,只有两个按键K1,K2。 我们看右边的高电平为3V3,但是我们的GPIO对于这个是有限制的,所以我们在前面接了一个限流电阻(R4,R5,R7,R11),当按键没有按下的时候,默认接地,为低电平;按键按下之后,就变成了高电平。因为PA0有自动唤醒的功能wakeup,而wakeup一定要是上升沿才能唤醒的,为了统一风格,所以是上升沿输入。

        电路图中的电容又有什么用呢?之前在学51单片机的时候,我们采取的消抖方式为软件消抖,我们这个是机械按键,需要延时20ms(消抖是前后都要消抖),要不然就会像交流电一样不断接通3.3V,如果我们接了这个电容的话,就会一直给电容充放电,直到稳定。之后无论是按下还是抬起,电容也在不断的充放电,对我们的电路没有影响。所以我们就不需要软件消抖。如果等于高电平,我们就确认按键按下了,如果等于低电平,我们就抬起了按键,进行相应的动作。

端口输入数据寄存器(GPIOx_IDR)

         很显然,这个寄存器还是配置低位的寄存器,不做更改时为0,若配置某位为1,即接通3.3V,变为高电平。

编写程序

        我们现在还没讲中断,等以后我们还会写中断函数(类似51单片机)

配置以及编写bsp_key文件

        我们先打开bsp_key.h文件,定义KEY1和KEY2的宏定义,包括打开时钟,宏定义接口以及设定Pin的值为0和13。

#define    KEY1_GPIO_CLK     RCC_APB2Periph_GPIOA
#define    KEY1_GPIO_PORT    GPIOA			   
#define    KEY1_GPIO_PIN	 GPIO_Pin_0#define    KEY2_GPIO_CLK     RCC_APB2Periph_GPIOC
#define    KEY2_GPIO_PORT    GPIOC		   
#define    KEY2_GPIO_PIN	 GPIO_Pin_13

        定义好之后,类似bsp_led.c中,我们打开bsp_key.c,然后创建一个函数LED_KEY_Config(void),然后再该函数中定义结构体类型,打开APB2上的时钟,配置模式以及初始化GPIO。

void LED_KEY_Config(void)
{GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK,ENABLE);GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_PIN;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(KEY1_GPIO_PORT,&GPIO_InitStruct);  //&地址即可
}

        然后我们要创建一个按键检测的函数。刚刚讲过我们的按键是硬件消抖,所以我们这里就不再需要进行delay函数的消抖。我们宏定义按键按下为KEY_ON,释放按键为KEY_OFF;

#define KEY_ON     1
#define KEY_OFF    0

        紧接着我们编写函数,由于有返回值,我们使用uint8_t写函数,先使用if检测是否有按键按下,如果没有就是OFF。然后在按下之后,我们需要检测是否松手,也就是按键的释放。使用while关键字检测是否一直为按下状态。(这里使用了GPIO_ReadInputDataBit函数,用来读取按键的状态):

uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{			/*检测是否有按键按下 */if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )  {	 /*等待按键释放 */while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);   return 	KEY_ON;	 }elsereturn KEY_OFF;
}

        这样我们就编写完成函数,记得要声明一下:

void Key_GPIO_Config(void);
uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);

        到这里我们的bsp_key的函数就全部编写完成了,接下来编写其他函数。

main函数编程

        我们在这里首先引用Key_GPIO_ConfiG();来初始化函数。然后在while循环中写一个if语句,如果按键检测结果为KEY_ON,则使LED1翻转,即LED1_TOGGLE;复制这段代码,拷贝一份到下面,检测按键2的状态。这就是主函数中的代码,接下来我们配置TOGGLE函数以及bsp_led中的函数及代码。

#include "stm32f10x.h"   // 相当于51单片机中的  #include <reg51.h>
#include "bsp_led.h"
#include "bsp_key.h"void Delay(uint32_t count)
{for(;count!=0;count--);
}int main(void)
{	LED_GPIO_Config();Key_GPIO_Config();while(1)                            {	   if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON  ){LED1(ON);}if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON  ){LED2_TOGGLE;}	}
}

bsp_led.c以及bsp_led.h文件函数编程

        我们先编写宏定义LED连接的GPIO端口RGB。

/* 定义LED连接的GPIO端口, 用户只需要修改下面的代码即可改变控制的LED引脚 */
// R-红色
#define LED1_GPIO_PORT    	GPIOB			            /* GPIO端口 */
#define LED1_GPIO_CLK 	    RCC_APB2Periph_GPIOB		/* GPIO端口时钟 */
#define LED1_GPIO_PIN		GPIO_Pin_5		        	/* 连接到SCL时钟线的GPIO */// G-绿色
#define LED2_GPIO_PORT    	GPIOB
#define LED2_GPIO_CLK 	    RCC_APB2Periph_GPIOB
#define LED2_GPIO_PIN		GPIO_Pin_0// B-蓝色
#define LED3_GPIO_PORT    	GPIOB
#define LED3_GPIO_CLK 	    RCC_APB2Periph_GPIOB
#define LED3_GPIO_PIN		GPIO_Pin_1#define ON     1
#define OFF    0

        如果我们想实现翻转LED灯,可以通过控制寄存器的方法,也可以通过控制标准的固件库的方法来控制io口。

使用固件库控制io口

        本节课刚开始就介绍了带参宏的定义,我们可以通过这个办法来控制:

/* 使用标准的固件库控制IO*/
#define LED1(a)	if (a)	\GPIO_SetBits(LED1_GPIO_PORT,LED1_GPIO_PIN);\else		\GPIO_ResetBits(LED1_GPIO_PORT,LED1_GPIO_PIN)#define LED2(a)	if (a)	\GPIO_SetBits(LED2_GPIO_PORT,LED2_GPIO_PIN);\else		\GPIO_ResetBits(LED2_GPIO_PORT,LED2_GPIO_PIN)#define LED3(a)	if (a)	\GPIO_SetBits(LED3_GPIO_PORT,LED3_GPIO_PIN);\else		\GPIO_ResetBits(LED3_GPIO_PORT,LED3_GPIO_PIN)
直接操作寄存器的方法控制IO

        在使用这个方法之前,我们先介绍一下C语言中的异或二进制运算符^。0^1为1,1^1为0;而0^0为0,1^0为1,然后我们就可以控制io口。我们既需要操作BSRR和BRR寄存器,也需要操作ODR寄存器,分别输出高电平,低电平以及输出反转状态。

/* 直接操作寄存器的方法控制IO */
#define	digitalHi(p,i)		   {p->BSRR=i;}	   //输出为高电平		
#define digitalLo(p,i)		   {p->BRR=i;}	   //输出低电平
#define digitalToggle(p,i)     {p->ODR ^=i;}   //输出反转状态/* 定义控制IO的宏 */
#define LED1_TOGGLE		   digitalToggle(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_OFF		   digitalHi(LED1_GPIO_PORT,LED1_GPIO_PIN)
#define LED1_ON			   digitalLo(LED1_GPIO_PORT,LED1_GPIO_PIN)#define LED2_TOGGLE		   digitalToggle(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED2_OFF		   digitalHi(LED2_GPIO_PORT,LED2_GPIO_PIN)
#define LED2_ON			   digitalLo(LED2_GPIO_PORT,LED2_GPIO_PIN)#define LED3_TOGGLE		   digitalToggle(LED3_GPIO_PORT,LED3_GPIO_PIN)
#define LED3_OFF		   digitalHi(LED3_GPIO_PORT,LED3_GPIO_PIN)
#define LED3_ON			   digitalLo(LED3_GPIO_PORT,LED3_GPIO_PIN)

        然后我们就可以使用三原色来进行混色:(基本混色)

/* 基本混色,后面高级用法使用PWM可混出全彩颜色,且效果更好 */
//红
#define LED_RED  \LED1_ON;\LED2_OFF\LED3_OFF//绿
#define LED_GREEN		\LED1_OFF;\LED2_ON\LED3_OFF//蓝
#define LED_BLUE	\LED1_OFF;\LED2_OFF\LED3_ON//黄(红+绿)					
#define LED_YELLOW	\LED1_ON;\LED2_ON\LED3_OFF//紫(红+蓝)
#define LED_PURPLE	\LED1_ON;\LED2_OFF\LED3_ON//青(绿+蓝)
#define LED_CYAN \LED1_OFF;\LED2_ON\LED3_ON//白(红+绿+蓝)
#define LED_WHITE	\LED1_ON;\LED2_ON\LED3_ON//黑(全部关闭)
#define LED_RGBOFF	\LED1_OFF;\LED2_OFF\LED3_OFF

         在bsp_led.c文件中,我们需要配置初始化结构体,然后打开时钟(有选择性);然后紧接着设置模式以及速度。(都是前几节课熟知的,不在多讲)然后就是通过控制3个Pin的值然后初始化GPIO口;并附带关闭所有LED灯的代码:

void LED_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( LED1_GPIO_CLK | LED2_GPIO_CLK | LED3_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure);	 //&地址即可GPIO_InitStructure.GPIO_Pin = LED2_GPIO_PIN;GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = LED3_GPIO_PIN;GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);/* 关闭所有led灯	*/GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);GPIO_SetBits(LED2_GPIO_PORT, LED2_GPIO_PIN);	 GPIO_SetBits(LED3_GPIO_PORT, LED3_GPIO_PIN);
}

        如果断言错误,我们执行如下代码:

void assert_failed(uint8_t* file, uint32_t line)
{// 断言错误时执行的代码LED1_ON;
}

小结

        到这里我们就写完了所有代码,以及代码的讲解(两种方式控制io口)。下节课我们学习位带操作。

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

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

相关文章

SpringBoot(Lombok + Spring Initailizr + yaml)

1.Lombok 1.基本介绍 2.应用实例 1.pom.xml 引入Lombok&#xff0c;使用版本仲裁 <!--导入springboot父工程--><parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version&g…

arcgis在GIS滑坡易发性分析中的应用技术研究

我国是地质灾害多发国家&#xff0c;地质灾害的发生无论是对于地质环境还是人类生命财产的安全都会带来较大的威胁&#xff0c;因此需要开展地质灾害风险普查。利用遥感&#xff08;RS&#xff09;技术进行地质灾害调查工作具有宏观、快速、准确的特点&#xff0c;能反映出地质…

空调 USACO2021

题目描述&#xff1a; 思路&#xff1a; 此题非常有技巧&#xff0c;我们首先可以先把希望温度和实际温度做差&#xff0c; 问题就转化成&#xff0c;把这个温度差如何去全都变为0&#xff0c;相对应的变成希望温度 也就是 去给温度差数组去做差分&#xff0c;因为&#xff0…

【正则表达式】正则表达式里使用变量

码 const shuai No My Name Is ShuaiGe.match(new RegExp(shuai, gi)); //↑↑↑↑↑↑↑↑ //等同于 //↓↓↓↓↓↓↓↓ /No/.test(My Name Is ShuaiGe)用作领域 搜索的字符动态改变&#xff0c;例如↓模糊搜索例&#xff1a; 一个文本宽&#xff0c;输入文本模糊搜索用户…

SpringCloud Gateway 新一代网关

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第六篇&#xff0c;即介绍 Gateway 新一代网关。 二、概述 2.1 Gateway 是什么 Gateway 是在 Spring 生…

基于SSM的协同过滤算法的电影推荐系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的协同过滤算法的电影推荐系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:TextArea)

多行文本输入框组件&#xff0c;当输入的文本内容超过组件宽度时会自动换行显示。 高度未设置时&#xff0c;组件无默认高度&#xff0c;自适应内容高度。宽度未设置时&#xff0c;默认撑满最大宽度。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&…

前端面试 ===> 【Vue2】

Vue2 相关面试题总结 1. 谈谈对Vue的理解 Vue是一种用于构建用户页面的渐进式JavaScript框架&#xff0c;也是一个创建SPA单页面应用的Web应用框架&#xff0c;Vue的核心是 数据驱动试图&#xff0c;通过组件内特定的方法实现视图和模型的交互&#xff1b;特性&#xff1a;&a…

选型|匠芯创工业级显示控制MCU

D13x系列微控制器 匠芯创D13x系列是一款基于RISC-V架构的高性能、国产自主、工业级跨界MCU&#xff0c;配备强大的2D图形加速、PNG解码、JPEG编解码引擎&#xff0c;具有丰富的屏接口&#xff0c;具有工业宽温、高可靠性、高开放性&#xff0c;可广泛应用于工业HMI、网关、串口…

解决vue2+elementUI的下拉框出现自动校验的问题

问题&#xff1a; 总结原因是因为新增的时候&#xff0c;传了空值进去 可以这样子解决 this.formData.value && this.$set(this.model, this.formData.key, this.formData.value)这种是只有值存在的时候才会给他赋值&#xff0c;但是这只解决单选下拉框&#xff0c;…

隧道技术和代理技术(三)

隧道技术 知识点 -隧道技术&#xff1a;解决不出网协议上线的问题&#xff08;利用出网协议进行封装出网&#xff09; -代理技术&#xff1a;解决网络通讯不通的问题&#xff08;利用跳板机建立节点后续操作&#xff09; 内环境示意图&#xff0c;方便理解 思路&#xff1a;…

【Mac】鼠标控制\移动\调整窗口大小BBT|边缘触发调整音量\切换桌面

一直在 win 习惯了通过鼠标的侧键来控制窗口的位置、大小&#xff0c;现在找到心的解决方案了&#xff0c;通过 BBT 设置侧键按下\抬起几颗。 以下解决方案的截图&#xff0c;其中还包括了其他操作优化方案&#xff1b; 滚轮配合 cmd 键调节页面大小&#xff1b;配合 option 键…

鸿蒙开发面试真题分享~

1. 在鸿蒙应用开发中&#xff0c;有哪些常用的性能优化策略和技术手段&#xff0c;如启动速度优化、内存管理优化、功耗控制等&#xff1f; 参考答案&#xff1a; 2. 鸿蒙系统强调跨平台特性&#xff0c;你会如何利用这一特性来优化多端部署和适配&#xff1f; 参考答案&…

Nuxt3 初学,基础配置,页面结构搭建,引入element

1.下载Nuxt框架 Nuxt 中文站 - 直观的Web框架 Nuxt3文档 NuxtNuxt是一个开源框架&#xff0c;它使web开发直观而强大。自信地创建高性能和生产级全栈web应用程序和网站。https://www.nuxt.com.cn/根据官方文档进行配置 2.配置页面 1.主要页面结构 导航栏内容底部 1.在comp…

YOLOv8独家改进:backbone改进 | TransXNet:聚合全局和局部信息的全新CNN-Transformer视觉主干| CVPR2024

💡💡💡本文独家改进:CVPR2024 TransXNet助力检测,代替YOLOv8 Backbone 改进结构图如下: 收录 YOLOv8原创自研 https://blog.csdn.net/m0_63774211/category_12511737.html?spm=1001.2014.3001.5482 💡💡💡全网独家首发创新(原创),适合paper !!! 💡…

Vcenter esxi web界面访问提示权限被拒绝

一、问题现象 原因 应该是在vCenter中添加主机的时候&#xff0c;将锁定模式设置成了严格。 二、解决过程 2.1 方式一 BMC登录主机&#xff0c;连接显示器和键盘。 输入账号密码&#xff0c;按F2进行设置&#xff0c;将会打开一个界面&#xff0c;第一个选项是设置密码&…

一台服务器部署两个独立的mysql实例

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…

【C++】string进一步介绍

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. 前言2. 迭代器2.1 反向迭代器2.2 const对象迭代器 3. Capacity3.1 size和length3.2 max_size3.3 capacity3.4 clear3.5 shrink_to_fit &#xff08;了解即可&#xff09;3.6 reserve3.7 resize 4. Element access4…

离线数仓(七)【DIM 层开发】

前言 今天开始 DIM 层的开发&#xff0c;说开发好像有点不配&#xff0c;还只是学习阶段&#xff0c;离开发还有很长的路要走。 一个人想象自己不懂得的事很容易浪漫。 --《沉默的大多数》王小波 1、DIM 层开发 DIM层设计要点&#xff1a; DI…

海豚调度系列之:任务类型——Apache SeaTunnel

海豚调度系列之&#xff1a;任务类型——Apache SeaTunnel 一、Apache SeaTunnel二、创建任务三、任务参数四、任务样例1.在 DolphinScheduler 中配置 SeaTunnel 环境2.配置 SeaTunnel 任务节点 一、Apache SeaTunnel SeaTunnel 任务类型&#xff0c;用于创建并执行 SeaTunnel…