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.
* 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);
上一篇:LCD1602单片机(STC51/STM32)驱动程序详解
下一篇:STM32串口接收不定长数据(接收中断+超时判断)
推荐阅读最新更新时间:2026-03-22 14:54
- LT3088IDD 宽安全工作区电源的典型应用
- 使用 Analog Devices 的 LT3663IDCB-3.3 的参考设计
- ADR425 可编程 DAC 参考的典型应用
- LT4276BIUFD 25.5W(类型 2)PoE+ 电源在反激模式下的典型应用电路,具有 24V、1A 输出
- 具有浪涌电流限制的低待机损耗功率前端
- LT4275AHMS IEEE 802.3at(类型 2)25.5W 受电设备的典型应用电路
- 采用 MSP430 电容式触控 MCU、触觉元件和 LCD 的 MSP432 MCU 参考设计
- 具有 6uA 反向泄漏电流的 LT1767EMS8E-3.3 双源电源的典型应用电路
- DER-282 - 使用HiperLCSTM LCS700HG设计的100 W超薄 (11 mm) LLC DC-DC转换器
- UART转USB桥接器



STM32模拟串口
dm9000cep网卡通信
正点原子I.MX6U嵌入式Qt开发指南
现代雷达系统的信号设计
BFR340T






京公网安备 11010802033920号