其他分享
首页 > 其他分享> > HAL库教程3:引脚输入检测

HAL库教程3:引脚输入检测

作者:互联网

使用CubeMX配置输入引脚

  本章我们要把按键作为输入源,使用单片机来检测引脚的电平状态。首先要查看原理图,按键与那些引脚相连。
在这里插入图片描述
  我使用的板子,按键K2 -K5分别对应PA4-PA7,且按键按下去以后,引脚接地。因此,我们要将单片机的PA4-PA7设置为上拉输入。
在这里插入图片描述

在这里插入图片描述

  点击生成代码并打开工程,可以看到STM32CubeMX配置好的引脚输入初始化代码如下(已省略部分无关代码):

//main.c
static void MX_GPIO_Init(void)
{
  /*Configure GPIO pins : PA4 PA5 PA6 PA7 */
 GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
 GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
 GPIO_InitStruct.Pull = GPIO_PULLUP;
 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

按键的输入、消抖与松手检测

  按键检测可以调用库函数HAL_GPIO_ReadPin,也可以使用位带操作PAin(n)。其实,只需要一步跳转,就可以发现HAL_GPIO_ReadPin其实也是在调用IDR寄存器而已。

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  GPIO_PinState bitstatus;
  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
  {
    bitstatus = GPIO_PIN_SET;
  }
  else
  {
    bitstatus = GPIO_PIN_RESET;
  }
  return bitstatus;
}

  为了提高程序的可读性,使用宏定义将按键与引脚关联起来。注意,代码只允许填写在USER CODE包含的区域,否则使用STM32CubeMX时,会删除区域外的代码。

//main.h
/* USER CODE BEGIN EM */
#define LED1 PCout(10)
#define LED2 PCout(11)
#define KEY_D   HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)
#define KEY_C   HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)
#define KEY_B   HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)
#define KEY_A   HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)
/* USER CODE END EM */

  在主函数的死循环中,可以编写代码来获取引脚的电平状态,并且用LED作为状态指示。注意要带松手检测。

//main.c main()
 while (1)
 {
   if(0 == KEY_A)
   {
     HAL_Delay(10);
     while(!KEY_A)
         ;
     LED1 = !LED1;
   }
   if(0 == KEY_B)
   {
     HAL_Delay(10);
     while(!KEY_B)
         ;
     LED2 = !LED2;
   }
}

新增c文件与按键扫描函数

  我们接下来尝试编写一个按键扫描函数。然而,如果新增的函数都放在main.c,那么main.c会变得很臃肿,既不方便代码阅读,又不方便理清程序的分层与架构。一般情况下,不同的函数要放在不同的c文件中。
  接下来按照CubeMX生成的工程的架构,新建IO.c与IO.h文件。
在这里插入图片描述
  将IO.c文件添加到工程中。
在这里插入图片描述
  头文件无需手动添加,只需在c文件中包含即可。我参照了正点原子的按键扫描函数,把按键扫描函数剪贴到IO.c中,并添加一些函数说明信息。

//IO.c
#include "IO.h"

/**
  * @brief 按键扫描函数
  * @param 模式,是否支持连按(长按)
  * @retval 按下的键值
  */    
u8 KEY_Scan(u8 mode)
{
  static u8 key_up=1;//按键按松开标志
  if(mode)key_up=1;  //支持连按          
  if(key_up&&(KEY_A==0||KEY_B==0||KEY_C==0||KEY_D==0))
  {
    HAL_Delay(10);//去抖动
    key_up=0;
    if(KEY_A==0)return KEY_A_PRES;
    else if(KEY_B==0)return KEY_B_PRES;
    else if(KEY_C==0)return KEY_C_PRES;
    else if(KEY_D==0)return KEY_D_PRES;
  }else if(KEY_A==1&&KEY_B==1&&KEY_C==1&&KEY_D==1)key_up=1;         
  return 0;// 无按键按下
}

在IO.h中定义一些IO操作的宏定义

#ifndef __IO_H
#define __IO_H

#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"

#define LED1 PCout(10)
#define LED2 PCout(11)
#define KEY_D   HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)
#define KEY_C   HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_5)
#define KEY_B   HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)
#define KEY_A   HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)

#define KEY_A_PRES    5    
#define KEY_B_PRES    4    
#define KEY_C_PRES    3    
#define KEY_D_PRES    2      

u8 KEY_Scan(u8 mode);

#ifdef __cplusplus
}
#endif

#endif

  在主函数死循环中,可以使用switch-case语法,把函数的返回值作为判断条件。

//main.c main()
 while (1)
 {
   switch(KEY_Scan(0))
   {
     case KEY_A_PRES: LED1 = !LED1; break;
     case KEY_B_PRES: LED2 = !LED2; break;
     case KEY_C_PRES: LED1 = !LED2; break;
     case KEY_D_PRES: LED2 = !LED1; break;
     default: break;    
   }
 }

标签:教程,HAL,PIN,引脚,KEY,GPIO,PRES,define
来源: https://blog.csdn.net/geek_monkey/article/details/89164496