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的按键检测,和其他灯状态的改变。