GPIO输入——按键检测

前言

上周学习了GPIO的输出,而这周学习GPIO的输入,我们接下来通过按键改变外部电平的状态,然后通过GPIO输入读取这个电平的状态。

程序实现效果

当K1按键按下一次时,绿灯便改变一次状态,即由亮变暗,由暗变亮。

硬件设计

在这里插入图片描述

K1与PA0相连,K2与PC13相连,当按键未按下时,PA0与PC13接地,输入0;当按键按下时,3.3V电压与PA0和PC13相连,输入1。
值得注意的是按键电路图中有一个电容,在电流不稳定时,不断充放电,达到稳定状态后,可将其中的电释放释放至GND中,实现硬件消抖。因此在写程序时不必写Delay函数,以实现软件消抖。
在这里插入图片描述
绿灯与PB0相连,PA0输出低电压,绿灯亮,输出高电平,绿灯灭。

GPIO输入需要操作的寄存器

端口配置低寄存器(GPIOx_CRL) (x=A…E),端口配置高寄存器(GPIOx_CRH) (x=A…E)

控制GPIO的输入输出及其模式
在这里插入图片描述
在这里插入图片描述

端口输入数据寄存器(GPIOx_IDR) (x=A…E)

读出对应GPIO口的电平变化,已确定按键被按下,然后做出相应操作

在这里插入图片描述

代码实现

初始化PA0口

void KEY1_GPIO_Config(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK,ENABLE);//打开GPIOA时钟
	
	GPIO_InitStruct.GPIO_Pin=KEY1_GPIO_PIN; 
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入模式
	
	GPIO_Init(KEY1_GPIO_PORT,&GPIO_InitStruct);//配置GPIOA
}

与上周初始化GPIO输出所用函数相同,只不过将模式转变为浮空输入模式,因不需要输出,所以不必配置最大速度

按键扫描

uint8_t KEY_Scan(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)//按键扫描
{
	if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)==1)
	{
		//松手检测
		while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)==1);
		return 1;
	}
	else return 0;
}

以上是按键扫描的代码,其中有松手检测这一代码,也就是若按键按下则进入循环,只有输入低电平,即松开按键后才会有返回值,做出后续反应。若删去这一段,则会在按键按下的瞬间做出反应,以后应根据实际情况不同选择需不需要按键检测

初始化PB0

void LED_GPIO_Config(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//打开GPIOB时钟
	
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);//配置GPIOB
}
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/2301_79590574/article/details/136410872

设置为推挽输出模式,最大速度为50Mhz以点亮绿灯

实现绿灯状态改变

void LED_G_TOGGLE(void{GPIOB->ODR^= GPIO_Pin_0;}

这是操作GPIO的ODR寄存器,即输出寄存器
在stm32f10x_gpio.h函数中GPIO_Pin_0被定义为(uint16_t)0x0001
它不断与ODR寄存器的第一位异或,使第一位由1变成0,又由0变成1。

异或

^是异或的符号
与1异或改变,与0异或不改变(相同为0,相异为1)
假设ODR寄存器第一位本为1,与1异或变为0(1^1=0),输出改变。
之后继续与1异或,变为1(0^1=1),输出改变,之后也是同样道理

按键按下后LED状态改变

if(KEY_Scan(GPIOA,GPIO_Pin_0)==1)
		{
			LED_G_TOGGLE;
		}

即每按下一次按键,LED灯的状态改变一次

代码优化

为增加代码的可植入性,可读性,可采用宏定义和模块化编程

最终代码

main.c

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h"

int main()
{
   LED_G_GPIO_Config();
   KEY1_GPIO_Config();
	while(1)
	{
		if(KEY_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN)==KEY_ON)
		{
			LED_G_TOGGLE;
		}

bsp_key.c

#include "bsp_key.h"

void KEY1_GPIO_Config(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK,ENABLE);//打开GPIOA时钟
	
	GPIO_InitStruct.GPIO_Pin=KEY1_GPIO_PIN;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	
	GPIO_Init(KEY1_GPIO_PORT,&GPIO_InitStruct);//配置GPIOA
}

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;
	}
	else return KEY_OFF;
}

bsp_key.h

#ifndef __BSP_key_H
#define __BSP_key_H

#include "stm32f10x.h"

#define KEY_ON              1
#define KEY_OFF             0

#define KEY1_GPIO_PIN     GPIO_Pin_0
#define KEY1_GPIO_PORT    GPIOA
#define KEY1_GPIO_CLK     RCC_APB2Periph_GPIOA

void KEY1_GPIO_Config(void);

uint8_t KEY_Scan(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin);

#endif /*__BSP_key_H*/

bsp_led.c

#include "bsp_led.h"

void LED_G_GPIO_Config(void)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(LED_G_GPIO_CLK,ENABLE);//打开GPIOB时钟
	
	GPIO_InitStruct.GPIO_Pin=LED_G_GPIO_PIN;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(LED_G_GPIO_PORT,&GPIO_InitStruct);//配置GPIOB
}

bsp_led.h

#ifndef __BSP_LED_H
#define __BSP_LED_H

#include "stm32f10x.h"

#define LED_G_GPIO_PIN     GPIO_Pin_0
#define LED_G_GPIO_PORT    GPIOB
#define LED_G_GPIO_CLK     RCC_APB2Periph_GPIOB

#define LED_G_TOGGLE      {LED_G_GPIO_PORT->ODR^=LED_G_GPIO_PIN;}

void LED_G_GPIO_Config(void);

#endif /*__BSP_LED_H*/

至此全部代码已全部写完,通过相同的方法,可以实现K2的按键检测,和其他灯状态的改变。

  • 31
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值