《嵌入式-STM32开发指南》第二部分 基础篇 - 第3章 按键(HAL库)

发布者:EtherealMelody最新更新时间:2024-12-17 来源: jianshu关键字:嵌入式  STM32  开发指南  按键  HAL库 手机看文章 扫描二维码
随时随地手机看文章

3.1普通方式

3.1.1 普通方式工作原理

按键 GPIO 端口有两个方案可以选择,一是采用上拉输入模式,因为按键在没按下的时候,是默认为高电平的,采且内部上拉模式正好符合这个要求。第二个方案是直接采用浮空输入模式,因为按照硬件电路图,在芯片外部接了上拉电阻,其实就没必要再配置成内部上拉输入模式了,因为在外部上拉与内部上拉效果是一样的。

图1按键电路

3.1.2 STM32Cube生成工程

关于如何使用使用STM32Cube新建工程在前文已经讲解过了,这里直说配置GPIO部分内容。本文要实现按键功能,通过按键实现LED的亮灭。我门在第一个程序的基础上进行修改即可,不必每次都新建工程。根据图1所示的电路,KEY1的引脚是PA0,我们将PA0的GPIO设置为下拉的输入模式,保留3个LED的GPIO配置。

图2

初始化基本配置后,我们重新生成工程,接下来按键编程。

3.1.3普通方式的具体代码分析

在看代码前,我们先看看按键扫描编程的流程:

1)使能按键引脚时钟,本文的引脚是PA0;
2)初始化按键,即初始化GPIO机构体,在前文已经详细讲解过了;
3)在无限循环中不断读取PA0的电平值,同时进行按键消抖;
4)判断按键被按下时,进行相应的处理。

 GPIO 初始化配置

static void MX_GPIO_Init(void){
  GPIO_InitTypeDef GPIO_InitStruct = {0};

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

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PB0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pins : PG6 PG7 */
  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(GPIOG, &GPIO_InitStruct);}

按键与 LED 的 GPIO 初始化函数类似,区别只是在这个函数中,要开启的 GPIO 的端口时钟不一样,并且把检测按键用的引脚 Pin 的模式设置为适合按键应用的上拉输入模式(由于接了外部上拉电阻,也可以使用浮空输入,读者可自行修改代码做实验)。若 GPIO 被设置为输入模式,不需要设置 GPIO 端口的最大输出速度。

 按键状态监测及按键消抖

uint8_t Key_Scan(void)

{           

    if(HAL_GPIO_ReadPin(KEY_GPIO,GPIO_PIN_0) == KEY_DOWN_LEVEL ) 

    {      

        HAL_Delay(10);      

        if(HAL_GPIO_ReadPin(KEY_GPIO,GPIO_PIN_0) == KEY_DOWN_LEVEL )  

        {    

            while(HAL_GPIO_ReadPin(KEY_GPIO,GPIO_PIN_0) == KEY_DOWN_LEVEL);   

            return  KEY_DOWN;    

        }

        else

        {

            return KEY_UP;

        }

    }

    return KEY_UP;

}


相信延时消抖的原理大家在学习其他单片机时就已经了解了,本函数的功能就是扫描输入参数中指定的引脚,检测其电平变化,并作延时消抖处理,最终对按键消息进行确认。

  利用HAL_GPIO_ReadPin()函数读取输入数据,若从相应引脚读取的数据等于 0(KEY_DOWN),低电平,表明可能有按键按下,调用延时函数。否则返回 KEY_UP,表示按键没有被按下。
   延时之后再次利用 HAL_GPIO_ReadPin()函数读取输入数据,若依然为低电平,表明确实有按键被按下了。否则返回 KEY_UP,表示按键没有被按下。
   循环调用HAL_GPIO_ReadPin()函数一直检测按键的电平,直至按键被释放,被释放后,返回表示按键被按下的标志 KEY_DOWN。以上是按键消抖的流程,调用了一个库函数 HAL_GPIO_ReadPin()函数。输入参数为要读取的端口、引脚,返回引脚的输入电平状态,高电平为 1,低电平为 0。

Main函数如下:

/* USER CODE BEGIN Header */

/**

  ******************************************************************************

  * @file           : main.c

  * @brief          : Main program body

  ******************************************************************************

  * @attention

  *

  *

© Copyright (c) 2020 STMicroelectronics.

  * All rights reserved.

  *

  * This software component is licensed by ST under BSD 3-Clause license,

  * the 'License'; You may not use this file except in compliance with the

  * License. You may obtain a copy of the License at:

  *                        opensource.org/licenses/BSD-3-Clause

  *

  ******************************************************************************

  */

/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/

#include 'main.h'


/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */


/* USER CODE END Includes */


/* Private typedef -----------------------------------------------------------*/

/* USER CODE BEGIN PTD */

typedef enum{

    KEY_UP = 0,

    KEY_DOWN = 1,

}KEYState_Type;

/* USER CODE END PTD */


/* Private define ------------------------------------------------------------*/

/* USER CODE BEGIN PD */

#define KEY_GPIO GPIOA

#define KEY_GPIO_PIN GPIO_PIN_0

#define KEY_DOWN_LEVEL 1

/* USER CODE END PD */


/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PM */


/* USER CODE END PM */


/* Private variables ---------------------------------------------------------*/


/* USER CODE BEGIN PV */


/* USER CODE END PV */


/* Private function prototypes -----------------------------------------------*/

uint8_t Key_Scan(void);

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

/* USER CODE BEGIN PFP */


/* USER CODE END PFP */


/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */


/* USER CODE END 0 */


/**

  * @brief  The application entry point.

  * @retval int

  */

int main(void)

{

  /* USER CODE BEGIN 1 */


  /* USER CODE END 1 */


  /* MCU Configuration--------------------------------------------------------*/


  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

  HAL_Init();


  /* USER CODE BEGIN Init */


  /* USER CODE END Init */


  /* Configure the system clock */

  SystemClock_Config();


  /* USER CODE BEGIN SysInit */


  /* USER CODE END SysInit */


  /* Initialize all configured peripherals */

  MX_GPIO_Init();

  /* USER CODE BEGIN 2 */


  /* USER CODE END 2 */


  /* Infinite loop */

  /* USER CODE BEGIN WHILE */

  while (1)

  {

    /* USER CODE END WHILE */

        if(KEY_DOWN_LEVEL == Key_Scan())

        {

            HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);


            HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);


            HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);


        }

    /* USER CODE BEGIN 3 */

  }

  /* USER CODE END 3 */

}


/**

  * @brief Key Scan

  * @retval uint8_t

  */

uint8_t Key_Scan(void)

{           

    if(HAL_GPIO_ReadPin(KEY_GPIO,GPIO_PIN_0) == KEY_DOWN_LEVEL ) 

    {      

        HAL_Delay(10);      

        if(HAL_GPIO_ReadPin(KEY_GPIO,GPIO_PIN_0) == KEY_DOWN_LEVEL )  

        {    

            while(HAL_GPIO_ReadPin(KEY_GPIO,GPIO_PIN_0) == KEY_DOWN_LEVEL);   

            return  KEY_DOWN;    

        }

        else

        {

            return KEY_UP;

        }

    }


    return KEY_UP;

}


/**

  * @brief System Clock Configuration

  * @retval None

  */

void SystemClock_Config(void)

{

  RCC_OscInitTypeDef RCC_OscInitStruct = {0};

  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};


  /** Initializes the RCC Oscillators according to the specified parameters

  * in the RCC_OscInitTypeDef structure.

  */

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;

  RCC_OscInitStruct.HSEState = RCC_HSE_ON;

  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;

  RCC_OscInitStruct.HSIState = RCC_HSI_ON;

  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;

  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

  {

    Error_Handler();

  }

  /** Initializes the CPU, AHB and APB buses clocks

  */

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;

  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;


  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)

  {

    Error_Handler();

  }

}


/**

  * @brief GPIO Initialization Function

  * @param None

  * @retval None

  */

static void MX_GPIO_Init(void)

{

  GPIO_InitTypeDef GPIO_InitStruct = {0};


  /* GPIO Ports Clock Enable */

  __HAL_RCC_GPIOA_CLK_ENABLE();

  __HAL_RCC_GPIOB_CLK_ENABLE();

  __HAL_RCC_GPIOG_CLK_ENABLE();


  /*Configure GPIO pin Output Level */

  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);


  /*Configure GPIO pin Output Level */

  HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);

[1] [2] [3]
关键字:嵌入式  STM32  开发指南  按键  HAL库 引用地址:《嵌入式-STM32开发指南》第二部分 基础篇 - 第3章 按键(HAL库)

上一篇:LCD1602单片机(STC51/STM32)驱动程序详解
下一篇:STM32串口接收不定长数据(接收中断+超时判断)

推荐阅读最新更新时间:2026-03-22 14:54

嵌入式-STM32开发指南》第二部分 基础篇 - 第7章DMA(HAL库
一、移植BusyBox 1、下载BusyBox的源代码 下载地址:http://www.busybox.net/downloads/,此处下载busybox-1.20.2.tar.bz2。 2、解压并进入目录 #tar -xvf busybox-1.20.2.tar.bz2 #cd busybox-1.20.2 3、修改Makefile中的体系结构ARCH和交叉编译器前缀CROSS_COMPILE #VIM Makefile CROSS_COMPILE = arm-linux- ARCH = arm 4、配置BusyBox #make menuconfig 其他选项都是一些Linux基本命令选项,自己需要哪些命令就编译进去,一
[单片机]
《<font color='red'>嵌入式</font>-<font color='red'>STM32</font><font color='red'>开发指南</font>》第二部分 基础篇 - 第7章DMA(<font color='red'>HAL库</font>)
STM32使用HAL库开发指南
准备内容 好奇心,耐心,细心 一台电脑,并安装keil5,以及STM32CUBEMX等开发应用。 JLINK或者ST-LINK模块。 STM32开发板或者最小系统板(我选用STM32F103RET6模块,配置与逻辑大同小异)。 01创建工程 步骤 1:在STM32CubeMX中创建一个项目 打开STM32CubeMX软件,在右上方的“Project”标签下,选择“New Project”。 在主界面上选择你需要使用的STM32系列芯片型号。 在左侧的选项树中,选择你需要的外设配置和时钟设置,并进行相应的配置。你可以根据自己的需求勾选或取消勾选相应的外设。 生成完成后,你可以选择打开生成代码所在
[单片机]
<font color='red'>STM32</font>使用<font color='red'>HAL库</font><font color='red'>开发指南</font>
嵌入式-STM32开发指南》第一部分 入门篇 -第6章 STM32下载程序及调试
6.1 STM32的启动模式 STM32三种启动模式对应的存储介质均是芯片内置的,它们是: 1)用户闪存 = 芯片内置的Flash。 2)SRAM = 芯片内置的RAM区,就是内存啦。 3)系统存储器 = 芯片内部一块特定的区域,芯片出厂时在这个区域预置了一段Bootloader,就是通常说的ISP程序。这个区域的内容在芯片出厂后没有人能够修改或擦除,即它是一个ROM(只读)区。 在每个STM32的芯片上都有两个管脚BOOT0和BOOT1,这两个管脚在芯片复位时的电平状态决定了芯片复位后从哪个区域开始执行程序,见下表: 表1 启动模式 在系统复位后,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存。用户可以通过设置BO
[单片机]
嵌入式系统学习——STM32按键输入
之前写了两篇关于STM32 GPIO的介绍和运用,跑马灯用到了GPIO的推挽输出,但是对于输入还是没有用到,这次就运用一下GPIO的上拉输入。实验还是和以前51做的实验一样,就是判断按键的输入,然后控制LED灯。这次没有直接配置寄存器,而是调用库函数和位操作结合。 注:每一块开发板对应电路都不相同,编写代码需要对应自己的板子,本人两个LED灯对应的GPIO为:GPIOD13和GPIOD14,并且是共阴极。两个按键对应的GPIO为:GPIOC13和GPIOE0,并且共阴极。 首先,LED初始化和上一篇博客中的跑马灯初始化一样,只需拷贝就可以了。 LED初始化函数: #include sys.h
[单片机]
<font color='red'>嵌入式</font>系统学习——<font color='red'>STM32</font>之<font color='red'>按键</font>输入
嵌入式-stm32学习:按键检测
bsp_key.h #ifndef __KEY_H #define __KEY_H #include stm32f4xx.h //引脚定义 /*******************************************************/ #define KEY1_PIN GPIO_Pin_0 //GPIO引脚号 #define KEY1_GPIO_PORT GPIOA //GPIO端口A #define KEY1_GPIO_CLK RCC_AHB1Periph_GPIOA //GPIO端口时钟 #define KEY2_
[单片机]
STM32 嵌入式学习入门(3)——STM32F103 按键输入控制LED灯
按键是单片机上一个很重要的输入设备,也很容易掌握,只要明白了IO口最基本的使用,就可以操作按键了。 我们的目的是控制开发板上板载的三个按键来操作开发板上板载的两个LED灯实现亮或灭(按键第一次按下时灯亮,再按下时灯灭,以此类推)。 博主所用的开发板是正点原子的mini板(STM32F103RCT6)和战舰板(STM32F103ZET6),因此下面的内容的例子以这两款开发板为例,但是基本的原理对任何开发板来说都是一样的,只要自己的开发板上板载了按键和LED灯(这两个资源应该是所有开发板上都有的资源吧),然后查看自己开发板的数据手册和硬件电路图、原理图,找到按键和LED灯对应的IO口,就可以按照本文所介绍的流程使用按键控制LE
[单片机]
<font color='red'>STM32</font> <font color='red'>嵌入式</font>学习入门(3)——STM32F103 <font color='red'>按键</font>输入控制LED灯
STM32HAL库学习(二)CubeMx按键
首先是找到电路图,按键是高电平按下还是低电平按下 GPIO八种模式 https://blog.csdn.net/hailin0716/article/details/24333951 上拉电阻的目的是为了保证在无信号输入时输入端的电平为高电平。而在信号输入为低电平是输入端的电平应该也为低电平。 按键是按下时是高电平时,那无信号输入时要保持低电平,下拉输入 枚举KEYState_TypeDef 定义按键的两种状态 typedef enum{ KEY0_UP, KEY0_DOWN, KEY1_UP, KEY1_DOWN }KEYState_typedef; 函数有个 KEYState_TypeDef 类型的返回值
[单片机]
STM32<font color='red'>HAL库</font>学习(二)CubeMx<font color='red'>按键</font>
STM32 HAL库】 STM32H743的电源配置和时钟配置
文章内容偏向HAL库的移植和使用,以个人观点及了解为主,若与事实不符,则以www.st.com、www.stmcu.org.cn等平台为准。 使用的软件: VSCode(1.36版,带C/C++ IntelliSense插件) Keil MDK(5.26版) 芯片:STM32H743ZIT6(Nucleo-H743平台) 所使用的库:STM32Cube_FW_H7_V1.3.0,下载地址:https://www.st.com/content/st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-emb
[单片机]
【<font color='red'>STM32</font> <font color='red'>HAL库</font>】 STM32H743的电源配置和时钟配置
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved