8. GPIO输入—按键检测

按键检测使用到GPIO外设的基本输入功能,本章中不再赘述GPIO外设的概念,如您忘记了, 可重读前面第七章的“GPIO框图剖析”小节。

8.1. 硬件设计

按键机械触点断开、闭合时,由于触点的弹性作用,按键开关不会马上稳定接通或一下子断开,使用按键时会产生 按键抖动 中的带波纹信号,需要用软件消抖处理滤波,不方便输入检测。

图 7‑1 按键抖动说明图

本实验板连接的按键带硬件消抖功能,它利用电容充放电的延时,消除了波纹,从而简化软件的处理, 软件只需要直接检测引脚的电平即可,原理图如下所示

图 7‑2 按键原理图

从按键的原理图可知,开发板上提供用户可编程的按键有两个,分别连接到PB13以及PH7中。 这些按键在没有被按下的时候,GPIO引脚的输入状态为低电平(按键所在的电路不通,引脚接地), 当按键按下时,GPIO引脚的输入状态为高电平(按键所在的电路导通,引脚接到电源)。 只要我们检测引脚的输入电平,即可判断按键是否被按下。

若您使用的实验板按键的连接方式或引脚不一样, 只需要修改配置引脚即可,程序的控制原理相同。

8.2. 软件设计

STM32CubeIDE会根据我们的配置自动完成外设的初始化,我们只需要做的是正确得配置好引脚信息, 在主函数中添加我们想要实现的逻辑代码即可。

LED的原理图如下所示

图 7‑2 LED原理图

此次实验我们将使用SW4按键控制PG2引脚上的LED亮灭,使用SW5控制PB5引脚的LED亮灭。

8.2.1. 使用STM32CubeIDE配置按键引脚与LED引脚

在本次工程中我们将新建一个工程, 新建工程的步骤便不再赘述了,忘记的读者请自行回顾。

在本次工程上我们需要配置LED所在的引脚配置为输出模式, 将按键所在的引脚配置为输入模式。总的需要配置4个引脚。

配置LED引脚模式

选择LED所在的引脚将其配置成输出模式

图 7‑4 LED引脚配置 图 7‑5 LED引脚配置

同时记得设置Pin Reserved -> Cortex-M4,不然将无法生成相关GPIO的初始化代码

图 7‑6 LED引脚配置 图  LED引脚配置

配置按键引脚模式

选择按键所在引脚设置为输入模式

图 7‑8 按键引脚配置

设置Pin Reserved -> Cortex-M4

图 7‑9 按键引脚配置

同理另一个引脚也是同样的设置

图 7‑10 按键引脚配置 图 7‑10 按键引脚配置

现在已经完成了初步的引脚配置了,接下来进行进一步的引脚配置, 为了我们方便辨识每个引脚的作用,在User Label设置各个引脚的标签,如下图所示

图 7‑12 标签设置

同时可按照个人需要设置LED及按键引脚上的GPIO配置,在本次工程我们将LED引脚设置为以下模式 具体的配置内容可参照之前GPIO讲解章节。

图 7‑13 GPIO设置

按键所在引脚设置保持不变,默认为浮空输入,引脚上的电平完全由外部信号所决定, 只是设置了用户标签。

图 8-14 按键引脚配置

选择为每个外设生成独立的配置文件,并生成代码。

图 8-14 按键引脚配置

8.2.1.1. 查看生成的GPIO引脚初始化代码

gpio.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void MX_GPIO_Init(void)
{

   GPIO_InitTypeDef GPIO_InitStruct = {0};

   /* GPIO Ports Clock Enable */
   __HAL_RCC_GPIOG_CLK_ENABLE();
   __HAL_RCC_GPIOH_CLK_ENABLE();
   __HAL_RCC_GPIOB_CLK_ENABLE();

   /*Configure GPIO pin : PtPin */
   GPIO_InitStruct.Pin = LED1_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
   GPIO_InitStruct.Pull = GPIO_PULLUP;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
   HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct);

   /*Configure GPIO pin : PtPin */
   GPIO_InitStruct.Pin = KEY2_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   HAL_GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);

   /*Configure GPIO pin : PtPin */
   GPIO_InitStruct.Pin = LED2_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
   GPIO_InitStruct.Pull = GPIO_PULLUP;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
   HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);

   /*Configure GPIO pin : PtPin */
   GPIO_InitStruct.Pin = KEY1_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);

}

可以发现MX_GPIO_Init中已经生成了LED和按键所在引脚的配置信息,将LED所在引脚 设置为推挽输出模式,将按键所在引脚设置为浮空输入模式。

8.2.1.2. 添加用户逻辑控制代码

生成的代码已经帮我们完成了按键以及LED引脚初始化的工作了,而我们需要做的是将 工作重心放在功能的实现上,可见STM32CubeIDE为我们带来的便利。对于初学者来说是 很友好的,但想随心所欲地配置各个外设还需要我们对各种外设都有相应的了解。

我们往main函数主循环内添加如下代码

main.c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
while (1)
{
      if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_SET)
      {
         while(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_SET);
         HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
      }

      if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_SET)
      {
         while(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_SET);
         HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
      }

}

添加的代码很简单,基本思路如下:

按键在没有被按下的时,读取到的按键GPIO引脚电平为低,而当按键被按下时, 读取到的GPIO引脚电平为高。由此便可判断按键是否被按下,当按键被按下时, 等待按键松开防止不断触发LED翻转。可根据不同的需要设计自己的按键触发逻辑。

其中GPIO_PIN_SET定义在stm32mp1xx_hal_gpio.h文件中,当我们需要使用到某个外设时, 我们应当先去大致地浏览HAL库为我们提供的该外设的stm32mp1xx_hal_ppp.h以及stm32mp1xx_hal_ppp.h文件。 里面详细包含了各个操作函数说明,以及各个结构体的定义。

8.2.2. 进入调试验证

将板子设置为工程模式,进入调试模式(具体操作请参照 STM32MP157 Cortex-M4开发实验说明 ), 按下KEY1能够控制LED1引脚亮灭, 按下KEY2能够控制LED2引脚亮灭。