STM32 CubeMX GPIO 输入/输出按键点亮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


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;
}

添加头文件路径

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 */
}

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

  • 30
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当然可以!这里是一个使用STM32HAL库进行串口通信的简单实例: 首先,需要在CubeMX置串口。打开CubeMX并选择你的微控制器型号,然后点击"Peripherals"选项卡,在左侧的"USART"菜单下选择一个可用的串口。根据你的需求,置串口的参数,例如波特率、数据位、停止位等。最后点击"Pinout & Configuration"选项卡,将串口的引脚分给正确的GPIO引脚。 生成代码后,在你的工程中打开`main.c`文件,并添加以下代码: ```c #include "stm32fxxx_hal.h" UART_HandleTypeDef huart2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART2_UART_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART2_UART_Init(); uint8_t txData[] = "Hello, world!\r\n"; uint8_t rxData[20]; while (1) { HAL_UART_Transmit(&huart2, txData, sizeof(txData), HAL_MAX_DELAY); HAL_UART_Receive(&huart2, rxData, sizeof(rxData), HAL_MAX_DELAY); } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { while(1); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { while(1); } HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } static void MX_USART2_UART_Init(void) { huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart2) != HAL_OK) { while(1); } } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } ``` 这段代码初始化了系统时钟、GPIO和USART2串口。在主循环中,我们通过串口发送"Hello, world!\r\n",然后通过串口接收数据。 请注意,在上述代码中,我们使用了USART2串口和GPIOA的引脚2和3。如果你选择了不同的串口和引脚,请相应地修改代码。 希望这个例子能帮助到你!如有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾格北峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值