×
单片机 > 单片机程序设计 > 详情

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

发布时间:2020-06-18 发布时间:
|

使用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库  引脚  输入检测 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ARM 汇编的必知必会