当前位置:   article > 正文

STM32 CubeMX GPIO 输入/输出按键点亮LED灯实战 (超详细配高清图,附源码)_stm32cube-按键控制led

stm32cube-按键控制led

STM32 CubeMX GPIO 输入/输出实战 (超详细配高清图,附源码)

1. 环境准备

  1. 正点原子探索者 V2 (STM32F407ZGT6)
  2. STM32CubeMX 6.2.0
  3. STM32CubeIDE 1.14.0
  4. ST-Link V2

2. GPIO功能概述

STM32F407ZG有8个16引脚的GPIO端口,从PA到PH,还有一个12引脚的PI端口,这些GPIO端口都链接在AHB1总线上,最高时钟频率可以达到168MHz(如下图时钟树),GPIO引脚能承受5V电压。

Fig.1 时钟树

一个端口的16个GPIO引脚的功能可以单独配置,每个引脚的输入/输出数据可以单独读取或输出。一个GPIO引脚的内部结构如下图所示,其内部有双向保护二极管,有可配置的上拉或下拉电阻。每个GPIO引脚可以配置为多种工作模式。

根据数据表中列出的每个I/O端口的具体硬件特性,通用IO(GPIO)端口的每个端口位,可以通过软件在以下几种模式下单独配置:

  • 输入模式

  • 模拟模式

  • 输出模式

  • 复用功能模式

  • 外部中断/事件线

在复位期间和刚好复位后,备用功能和外部中断线不活跃,I/O端口配置为输入浮点模式。 所有GPIO引脚都有微弱的内部上拉和下拉电阻,可以激活或不激活。 在输出或备用模式下,每个IO可以配置为开漏或推挽类型,IO速度可以根据VDD值选择。 所有端口都有外部中断/事件功能。要使用外部中断线,端口必须配置为输入模式。所有可用的GPIO引脚都连接到16个外部中断/事件线,从EXTI0到EXTI15。 外部中断/事件控制器由多达23个边缘检测器(16条线连接到GPIO)组成,用于生成事件/中断请求(每个输入线可以独立配置,以选择类型 ) 。(中断或事件)和相应的触发器事件(上升或下降或两者)。每行也可以被独立屏蔽。

image-20231212205536541

3. 正点原子探索者原理图模块选择

从正点原子的原理图中,选择4个按键,2个LED灯作为本次实验的对象,用4个按键来控制2个LED灯实现不同功能的开关LED灯的效果。

image-20231214223415136

下图所示是4个按键KEY对应的原理图,及相应的配置功能

名称端口引脚功能特性初始电平
KEY_UPPA0Input modePull-down 下拉N/A
KEY2PE2Input modePull-up 上拉N/A
KEY1PE3Input modePull-up 上拉N/A
KEY0PE4Input modePull-up 上拉N/A
BuzzerPF8OutputPushpull推挽输出,初始低电平
LED1PF9OutputPushpull推挽输出,初始低电平
LED2PF10OutputPushpull推挽输出,初始低电平

image-20231214223643623

image-20231214223745496

image-20231214224526507

image-20231214224538399

4. STM32CubeMX配置过程

  1. 创建工程:选择STM32F407/417,MCU类型STM32F407ZGTx,封装Package选择LQFP144

image-20231214222206259

  1. 找到需要配置的端口PF8,鼠标右键写入自定义的名称

image-20231214221721606

  1. 写入Buzzer,作为自定义名称

image-20231214221754530

  1. 鼠标左键点击该端口,选择为GPIO_Output,作为输入引脚

image-20231214221959534

  1. 同理,按照上述操作,一次吸入名称LED1,LED2,并且将他们选为GPIO_Output

image-20231214222447711

  1. 点开左侧System Core选项,找到GPIO功能,按照下图说是方法依次配置输出和输入的GPIO端口

image-20231215081412323

  1. 根据原理图,设置按键的GPIO类型,由于KEY0,1,2都是上拉电阻,因此初始时为了保持开关断开,选择上拉电阻,KEY_UP则为下拉电阻

image-20231215081332437

  1. RCC模块配置:高速时钟选择外部晶振。

image-20231215081705567

  1. 调试口本例中选用ST-Link,则选择JTAG(4 PIN)

image-20231215081805184

  1. 时钟配置:在Input frequency出填写外部晶振8M,在HCLK处填写168MHz,即可自动计算时钟的分频和倍频系数

    image-20231226212731838

image-20231215082223542

  1. 选择CubeIDE进行编译和调试,如果选用Keil进行调试和编译,则选用MDK-ARM

image-20231215082504544

  1. 设置堆栈大小

image-20231225081716572

  1. 配置代码生成

image-20231225082240164

5. 代码实现

下面我们用STM32官方IDE(继承开发环境)–STM32CubeIDE来进行代码编写,编译和调试,它集成了STM32CubeMX配置工具和Eclipse集成开发环境,为开发人员提供了一个全面的工具套件来编写、编译和调试STM32微控制器的应用程序。2017年,为了取代被ARM公司Keil工具绑定,ST在当年收购Atollic公司,帮助其在原有的TrueStudio扩展到集编译、调试和仿真等于一体的集成开发环境,并完全面向用户免费,再配合其STM32CubeMX,可以达到从代码配置到调试等各个环节。

keyled.h
#include "main.h"

typedef enum {
	KEY_0 = 0,
	KEY_1,
	KEY_2,
	KEY_UP,
	KEY_NONE,
} KEYS;

KEYS ScanPressedKey(uint32_t timeout);

#define KEY_WAIT_ALWAYS		0

#ifdef LED1_Pin
	#define LED1_Toggle() 	HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin)
	#define LED1_ON() 		HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET)
	#define LED1_OFF() 		HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET)
#endif

#ifdef LED2_Pin
	#define LED2_Toggle() 	HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin)
	#define LED2_ON() 		HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET)
	#define LED2_OFF() 		HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET)
#endif

#ifdef Buzzer_Pin
	#define Buzzer_Toggle() 	HAL_GPIO_TogglePin(Buzzer_GPIO_Port, Buzzer_Pin)
	#define Buzzer_ON() 		HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET)
	#define Buzzer_OFF() 		HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET)
#endif


  • 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
keyled.c
#include "keyled.h"

/**
 * Scans 4 keys in a polling fashion and returns the key value.
 * timeout = 0 (ms) - If timeout = 0, it scans until a key is pressed.
 */
KEYS ScanPressedKey(uint32_t timeout)
{
	KEYS key = KEY_NONE;
	uint32_t tickstart = HAL_GetTick(); /* Get the Current time  */
	const uint32_t binDelay = 20;  /* Delay time for Key shake off */
	while (1)
	{

#ifdef KEY0_Pin
		if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
		{
			HAL_Delay(binDelay);
			if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
				return KEY_0;
		}
#endif
#ifdef KEY1_Pin
		if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET)
		{
			HAL_Delay(binDelay);
			if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET)
				return KEY_1;
		}
#endif

#ifdef KEY2_Pin
		if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET)
		{
			HAL_Delay(binDelay);
			if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET)
				return KEY_2;
		}
#endif
#ifdef KEY_UP_Pin
		if (HAL_GPIO_ReadPin(KEY_UP_GPIO_Port, KEY_UP_Pin) == GPIO_PIN_SET)
		{
			HAL_Delay(binDelay);
			if (HAL_GPIO_ReadPin(KEY_UP_GPIO_Port, KEY_UP_Pin) == GPIO_PIN_SET)
				return KEY_UP;
		}
#endif
		if (timeout != KEY_WAIT_ALWAYS)
		{
			if ((HAL_GetTick() - tickstart) > timeout)
				break;
		}

	}
	return key;
}

  • 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
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

添加头文件路径

image-20231225215909831

添加C源文件路径

image-20231225220005529

main.c
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)
  {
	  KEYS curKey = ScanPressedKey(KEY_WAIT_ALWAYS);
	  switch(curKey)
	  {
	  case KEY_0:
		  LED1_Toggle();
		  break;
	  case KEY_1:
		  LED2_Toggle();
		  break;
	  case KEY_2:
		  LED1_Toggle();
		  LED2_Toggle();
		  break;
	  case KEY_UP:
		  Buzzer_Toggle();
		  break;
	  default:
		  break;
	  }
	  HAL_Delay(200);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
  • 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
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

基于以上可以实现用轮询Polling的方式实时检测,按下相应的按键点亮LED灯和关闭LED灯的功能。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/618889
推荐阅读
相关标签
  

闽ICP备14008679号