实验二 按键检测—GPIO输入

一. 实验目标

1.通过编程检测普通按键KEY1和KEY2的状态,并通过LED1和LED2指示按键状态;

2.通过本实验掌握Keil
5新建工程、使用STM32库函数编写应用程序、将程序下载至实验板的步骤、方法;

3.通过本实验掌握STM32的GPIO外设的基本概念,掌握对GPIO输入状态进行读取和输出状态进行控制的基本方法。

二. 知识储备及设计思路

在上一节实验中用到GPIO配置输出IO口作为输出,本节我们需要用到输入IO口,需要使用IDR寄存器,其余需要配置的寄存器不在描述,IDR该寄存器用于读取GPIOx的输入数据,该寄存器各位描述见表:

该寄存器用于读取某个IO的电平,如果对应的位为0(IDRy=0),则说明该IO输入的是低电平,如果是1(IDRy=1),则表示输入的是高电平。HAL库操作该寄存器读取IO输入数据相关函数:

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

STM32F4的IO口做输入使用的时候,是通过调用函数HAL_GPIO_ReadPin
()来读取IO口的状态的。了解了这点,就可以开始我们的代码编写了。

三.引脚说明与硬件连接

图3.2.1(a) 普通按键KEY1,KEY2硬件连接图

图3.2.1(b) 普通按键KEY1,KEY2的管脚分配图

图3.2.1(c) LED1、LED2硬件连接图 图3.2.1(d) LED1、LED2管脚分配图

如图3.2.1(a)、(b)、(c)、(d)可知,普通按键KEY1、KEY2分别连接至GPIO PG6和PG7管脚,
LED1和LED2分别连接至GPIO
PF6和PF7管脚。当某一按键按下时,PG6(或PG7)为低电平,按键松开时则为高电平。当GPIO
PF6(或PF7)输出高电平时,LED1(或LED2)点亮,输出低电平时,LED1(或LED2)点灭。

由硬件连接图可知,当按键按下时,对应GPIO管脚电平为低电平(0V),当按键松开时,对应GPIO管脚为高电平(3.3V)。通过程序循环读取GPIO管脚的高、低电平,来判断当前按键的状态(按下或是松开)。

四.程序设计

根据检测到的按键状态,控制LED对应的GPIO分别输出高、低电平,来点亮或点灭对应的LED,指示当前按键的状态。

在主函数中,主要实现按键检测和led控制。代码如下:

int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); while (1) { if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_6)){ // 按键KEY1按下,点亮LED1 HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET); } else { // 按键KEY1松开,点灭LED1 HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET); } if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_7)){ // 按键KEY2按下,点亮LED2 HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET); } else { // 按键KEY2松开,点灭LED2 HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); } } }

main函数代码中while(1)循环中的代码。其中,代码分析如下:

读取GPIO PG6管脚的输入电平,并判断是否为低电平

如果为低电平,表示按键KEY1按下,则点亮LED1

如果为高电平,表示按键KEY1松开,则点灭LED1

读取GPIO PG7管脚的输入电平,并判断是否为低电平

如果为低电平,表示按键KEY2按下,则点亮LED2

如果为高电平,表示按键KEY2松开,则点灭LED2

接下来,将介绍使用CUBE生成的初始化函数MX_GPIO_Init,几个主要子函数的功能与内容。

void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOI_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); HAL_GPIO_WritePin(GPIOI,GPIO_PIN_10|GPIO_PIN_11,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOF,GPIO_PIN_6|GPIO_PIN_7,GPIO_PIN_RESET); GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); }

函数MX_GPIO_Init代码,是stm32cube自动生成的代码,其功能为对LED灯和按键对应的GPIO引脚进行初始化配置。程序实现功能为:

使能对应GPIO的时钟。

拉低对应的PF6和PF7引脚使LED1、LED2灯熄灭,作为初始状态。

配置PG6和PG7引脚为输入模式,无上拉或下拉,并通过函数HAL_GPIO_Init完成配置。

配置PF6和PF7引脚为输出模式,输出状态为推挽输出,输出速度为低速,无上拉或下拉,并通过函数HAL_GPIO_Init完成配置。

在这里用到了HAL_GPIO_Init函数,用于配置GPIO口。

void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);

五.实验结果

将编译好的代码下载到实验板中,按下复位键。

按下普通按键KEY1后,LED1点亮;松开KEY1后,LED1点灭。

按下普通按键KEY2后,LED2点亮;松开KEY2后,LED2点灭。

六.思考与拓展

1.本实验通过循环轮询GPIO的输入状态来实现按键检测,是否可以加入延迟函数来适当增大检测的间隔时间?检测的间隔时间多长较为合适?

2.按键所用的开关为机械弹性开关,由于弹性作用,按键开关闭合或断开瞬间会伴随一连串的抖动,因此要进行按键消抖。请尝试借助延迟函数实现按键消抖处理。

七.STM32CubeMx配置GPIO

在cube中将按键输入IO口配置为输入模式。