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.rhkb.cn/news/275481.html

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

相关文章

一文扫荡,12个可视化图表js库,收藏备用。

一、什么是可视化图表 可视化图表是通过图形化的方式将数据可视化展示出来的一种方式。它能够将复杂的数据以直观、易懂的形式呈现给用户&#xff0c;帮助用户更好地理解和分析数据。 可视化图表可以包括各种类型的图表&#xff0c;如线形图、柱状图、饼图、散点图、雷达图等。…

如何使用vue定义组件之——父组件调用子组件数据

首先&#xff0c;准备父子容器&#xff1a; <div class"container"><my-father></my-father><my-father></my-father><my-father></my-father><!-- 此处无法调用子组件&#xff0c;子组件必须依赖于父组件进行展示 --&…

【数据结构】双向链表及LRU缓存的实现

目录 前言 1. 在原有的自定义链表类 Linked 的基础上&#xff0c;添加新的 “节点添加”方法 addNode(Node node) 测试用例 测试结果 2. 在自定义链表类的基础上&#xff0c;使用双重循环“强力” 判断两个节点是否发生相交 测试用例 测试结果 3. 在自定义链表类的基础上…

Github 2024-03-14 Go开源项目日报 Top10

根据Github Trendings的统计,今日(2024-03-14统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Go项目9非开发语言项目1TypeScript项目1Ollama: 本地大型语言模型设置与运行 创建周期:248 天开发语言:Go协议类型:MIT LicenseStar数量:42…

【JVM】什么是运行时数据区?

什么是运行时数据区&#xff1f; 运行时数据区指的是JVM所管理的内存区域&#xff0c;其中分成两大类&#xff1a; 线程共享 – 方法区、堆 方法区&#xff1a;存放每一个加载的类的元信息、运行时常量池、字符串常量池。 堆&#xff1a;存放创建出来的对象。 线程不共享 – …

OpenResty使用Lua大全(三)OpenResty使用Json模块解析json

文章目录 系列文章索引一、使用Json模块1、引入cjson模块2、table转json字符串3、json字符串转table4、异常处理&#xff08;1&#xff09;异常复现&#xff08;2&#xff09;使用pcall命令&#xff08;3&#xff09;cjson.safe 模块 5、空table返回object还是array 系列文章索…

Python算法(列表排序)

一。冒泡排序&#xff1a; 列表每两个相邻的数&#xff0c;如果前面比后面大&#xff0c;则交换这两个数 一趟排序完成后&#xff0c;则无序区减少一个数&#xff0c;有序区增加一个数 时间复杂度&#xff1a;O(n*n) 优化后&#xff1a;已经排序好后立马停止&#xff0c;加快…

第十五届蓝桥杯(Web 应用开发)模拟赛 3 期-大学组(被题目描述坑惨了)

目录 1.创意广告牌 2.原子化css 3.神秘咒语 4.朋友圈 5.美食蛋白揭秘 6.营业状态变更 7.小说阅读器 8.冰岛人 9.这是一个”浏览器“ 10.趣味加密解密 总结 1.创意广告牌 这个题目不多说了&#xff0c;只要知道这些css应该都能写出来&#xff0c;不会的平时多查查文…

今天我们来学习一下关于MySQL数据库

目录 前言: 1.MySQL定义&#xff1a; 1.1基础概念&#xff1a; 1.1.1数据库&#xff08;Database&#xff09;&#xff1a; 1.1.2表&#xff08;Table&#xff09;&#xff1a; 1.1.3记录&#xff08;Record&#xff09;与字段&#xff08;Field&#xff09;&#xff1a; …

提升运营效率,探索运营中台架构的力量

随着数字化转型的加速推进&#xff0c;企业需要更高效地管理和运营各项业务&#xff0c;而运营中台架构作为一种新型的业务架构设计理念&#xff0c;正在逐渐受到关注和应用。本篇博客将深入探讨运营中台架构的概念、优势和实践&#xff0c;帮助企业了解如何通过构建运营中台实…

【智能硬件、大模型、LLM 智能音箱】MBO:基于树莓派、ChatGPT 的桌面机器人

MAKER:David Packman/译:趣无尽(转载请注明出处) 这是国外 Maker David Packman 制作的基于树莓派机器人 MBO,该机器人的外观设计灵感来自动漫 Adventure Time 中的机器人 MBO。它具有强大的交互功能,可实现脱机唤醒词检测、调用 ChatGPT 3.5 进行聊天、机器视觉对图像进…

Excel 性能:提高计算性能

计算速度的重要性 计算速度慢会影响生产力并增加用户错误。随着响应时间的延长&#xff0c;用户的工作效率和专注于任务的能力会下降。 Excel 有两种主要的计算模式&#xff0c;可让您控制何时进行计算&#xff1a; 自动计算- 当您进行更改时&#xff0c;公式会自动重新计算。…

自适应窗口图片轮播HTML代码

自适应窗口图片轮播HTML代码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 代码下载地址 自适应窗口图片轮播HTML代码

王庆:当下股市过于悲观,A股、港股基本完成补跌和普跌过程,逆向布局时机已到

核心观点&#xff1a; 1、房地产对中国经济增长拖累最严重的时期正在过去...密切关注真正拐点的出现。 2、当前资本市场从价格表现上来讲&#xff0c;表现的远远超过了基本面所决定的悲观程度。 由于当前资本市场过于悲观&#xff0c;那么反过来就是孕育着机会。 3、我们判…

Oracle 主从切换脚本

一、 切换前预检查 1. dg_precheck_main_v1.4.sh #!/bin/bash#********************************************************************************** # Author: Hehuyi_In # Date: 2022年06月16日 # FileName: dg_precheck_main_v1.4.sh # # For sys user, execute the sc…

Linux中udp服务端,客户端的开发

UDP通信相关函数&#xff1a; ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); 函数说明&#xff1a;接收信息 参数说明&#xff1a;sockfd:套接字buf:要接收的缓冲区len:缓冲区…

React Hooks 那些事儿

翻了波之前写的文章还有笔记&#xff0c;发现关于前端的文章并不多&#xff08;好歹也划水做过点前端开发&#xff09;。巧了&#xff0c;最近没什么好话题可写&#xff0c;做下 React Hooks 学习笔记吧。 Effect Hook 不得不说 Hook 的出现降低了我们在 React 中处理副作用&…

医药大数据案例分析

二、功能 &#xff08;1&#xff09;流量分析 &#xff08;2&#xff09;经营状态分析 &#xff08;3&#xff09;大数据可视化系统 配置tomcat vim /root/.bash_profile添加以下内容&#xff1a; export CATALINA_HOME/opt/tomcat export PATH P A T H : PATH: PATH:CATALIN…

构建社区服务平台的智慧架构

社区服务平台作为连接社区居民与各类服务资源的桥梁&#xff0c;承载着提升居民生活品质、促进社区发展的重要使命。本文将深入探讨社区服务平台的架构设计理念、核心功能和发展前景&#xff0c;助力读者了解如何构建智慧化、便捷化的社区服务平台&#xff0c;为社区居民提供更…

2024年:AI辅助研发领航新时代,颠覆性创新无处不在

随着时光荏苒&#xff0c;我们踏入了2024年——一个人工智能(AI)光芒四射的时代。从最初的逻辑推理程序到今日能自主创作艺术、编写复杂代码的智能体系&#xff0c;AI的发展可谓日新月异。 如今&#xff0c;它正以前所未有的速度和力度渗透到科技和工业研发的深层次领域&#…