【stm32】hal库学习笔记-GPIO按键控制LED和蜂鸣器(超详细!)

【stm32】hal库学习笔记-GPIO按键控制LED和蜂鸣器

注:本学习笔记基于stm32f4系列
使用的开发板为正点原子stmf407ZGT6探索者开发板

GPIO引脚使用时,可输入或输出数字信号
例如:
检测按键输入信号(Read_Pin)输出信号(Write_Pin)
输出信号点亮或熄灭LED

硬件特点

GPIO引脚内部结构图
GPIO引脚内部结构图

GPIO状态

  • 输入浮空状态:上拉下拉电阻均不使用(复位时状态)
  • 输入上拉状态:只使用上拉电阻-引脚外部无输入时读到的电平为高电平

这里是引用

按键按下时接地读到低电平

  • 输入下拉状态:只使用下拉电阻-引脚外部无输入时读到的电平为低电平

这里是引用

  • 模拟状态:不使用任何内部的上拉下拉电阻-用于ADC输入/DAC输出引脚
  • 开漏输出(Output Open Drain)
  • 推挽输出:输出1时引脚为高电平,输出0时引脚为低电平
    若要增强引脚的输出驱动能力,则可使用上拉-如GPIO输出高电平点亮LED
  • 复用功能推挽
  • 复用功能开漏

涉及到的函数

在这里插入图片描述

重要函数

HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

按键控制LED

LED部分原理图
LED部分原理图
按键部分原理图
按键部分原理图

实现功能:
按下KEY0时,使LED0的输出翻转
按下KEY1时,使LED1的输出翻转
按下KEY2时,使LED0与LED1的状态都翻转

MCU图形化配置

连接按键的引脚选择GPIO_Input
连接LED的引脚选择GPIO_Output
并设置相应的用户标签
在这里插入图片描述

  • KEY0,KEY1,KEY2配置为上拉(Pull-up)
  • PF9,PF10设置为推挽输出(Output Push Pull)
  • 调试引脚设为串行调试引脚WSD
    在这里插入图片描述
  • 在RCC里将HSE改为晶振
    在这里插入图片描述
    在时钟树界面
  • 将HSE改为8MHz
  • 主锁相环选择HSE作为时钟源
  • 设置HCLK为168

在这里插入图片描述

代码部分

编写驱动程序

keyled.c

#include "keyled.h"
//编写函数扫描被按下的按键
KEYS ScanPressedKey(uint32_t timeout)
{
	uint32_t tickstart=HAL_GetTick();
	const uint32_t btnDelay=20;//延时时间
	while(1)
	{
#ifdef KEY0_Pin
		if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET)
		{
			HAL_Delay(btnDelay);//延时消除前抖动
			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(btnDelay);
			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(btnDelay);
			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(btnDelay);
			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_NONE;
}//若没有按键被按下,超时后跳出循环

keyled.h

#include <main.h>
//创建枚举类型
typedef enum
{
	KEY_0=0,
	KEY_1,
	KEY_2,
	KEY_UP,
	KEY_NONE,
}KEYS;
//定义参数-表示一直等待按键按下
#define KEY_WAIT_ALWAYS		0//函数声明
KEYS ScanPressedKey(uint32_t timeout);
#ifdef LED0_Pin
	#define LED0_Toggle()	HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin)//实现翻转
	#define LED0_ON()	 HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PinState PinStateGPIO_PIN_SET)//实现打开
	#define LED0_OFF()	 HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET)//实现关闭
#endif

#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_PinState PinStateGPIO_PIN_SET)
	#define LED1_OFF()	 HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET)
#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_PinState PinStateGPIO_PIN_SET)
	#define Buzzer_OFF()	 HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET)
#endif

应用驱动程序

在这里插入图片描述
在这里插入图片描述
如此设置后出现no such file or directory,经过上网查找后找到如下解决办法
在这里插入图片描述
(来自CSDN博主tuxinbang1989)

编写主程序
/* USER CODE BEGIN Includes */
#include "keyled.h"
/* USER CODE END Includes */
  while (1)
  {
	  KEYS curKey=ScanPressedKey(KEY_WAIT_ALWAYS);
	  switch (curKey)
	  {
	  case KEY_0:
	  	  LED0_Toggle();
	  	  break;
	  case KEY_1:
	  	  LED1_Toggle();
	  	  break;
	  case KEY_2:
	  	  LED0_Toggle();
	  	  LED1_Toggle();
	  	  break;
	  case KEY_UP:
	  	  Buzzer_Toggle();
	  	  break;
	  default:
		  break;
	  }
	  HAL_Delay(200);//消除按键弹起时的的抖动影响

按键控制蜂鸣器

有源蜂鸣器原理图
有源蜂鸣器原理图
有源蜂鸣器是指自带了震荡电路的蜂鸣器,这种蜂鸣器一接上电就会自己震荡发声。而如
果是无源蜂鸣器,则需要外加一定频率(2~5Khz)的驱动信号,才会发声。
图中 Q4 是用来扩流,R65 则是一个下拉电阻,避免 MCU 复位的时候,蜂鸣器可能发声的
现象。BEEP 信号直接连接在 MCU 的 PF8 上面,PF8 可以做 PWM 输出,可使用 PWM 来控制蜂鸣器实现“唱歌”。

实现功能:
按下KEY_UP按键时,蜂鸣器输出翻转

MCU图形化配置

连接蜂鸣器的引脚选择GPIO_Output
并设置相应的用户标签

  • KEY_UP配置为下拉(Pull-down)
  • PF8设置为下拉推挽输出(Output Push Pull)
  • 将初始状态改为High(防止一复位蜂鸣器就响)
  • 最大输出频率-若为无源蜂鸣器则改为High,有源滤波器都可
    在这里插入图片描述

成果演示

在这里插入图片描述
上键翻转蜂鸣器状态
KEY0翻转红灯,KEY1翻转绿灯
KEY2同时翻转两个灯状态

  • 51
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32HAL库提供了许多函数来控制蜂鸣器。以下是一个简单的例子,演示如何使用STM32HAL库来驱动蜂鸣器: ```c #include "stm32f1xx_hal.h" TIM_HandleTypeDef htim2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2); while (1) { } } 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_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } 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(__FILE__, __LINE__); } } void MX_TIM2_Init(void) { TIM_MasterConfigTypeDef sMasterConfig; TIM_OC_InitTypeDef sConfigOC; htim2.Instance = TIM2; htim2.Init.Prescaler = 72 - 1; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 1000 - 1; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 500 - 1; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } void _Error_Handler(char *file, int line) { while(1) { } } ``` 在这个例子中,我们使用了TIM2_CH2 PWM输出1khz来驱动蜂鸣器。在`MX_TIM2_Init()`函数中,我们设置了TIM2的时钟分频器为72,计数模式为向上计数,周期为1000-1,占空比为50%。在`MX_GPIO_Init()`函数中,我们将PA1引脚配置为复用推挽输出模式。在`main()`函数中,我们启动了TIM2_CH2 PWM输出,并在while循环中等待。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值