前言:在前一篇《STM32WL开发之LORA评估板上通过GPIO控制LED》中已经基于易智联的LoRa评估板LM401-Pro-Kit介绍了在其Demo例程上如何实现GPIO控制LED闪烁的功能,本文将介绍如何基于LoRa评估板和Demo例程实现按键KEY的配置与应用。
功能描述
本文将基于Demo例程实现一个通过按键KEY控制LED闪灯,当按键KEY按下,LED灯闪灯一次。
STM32中按键的工作原理
STM32中GPIO引脚自带上拉、下拉输入,因此硬件电路部分不需要加额外的电阻实现上拉下拉。主要有以下两种方式实现独立按键设计:
(一)高电平检测独立按键:
只需要从VCC引线通过一个按键开关到单片机I/O口,软件初始化配置为下拉输入或浮空输入。当按键开关按下时开关导通,单片机I/O口就检测到高电平输入。
(二)低电平检测独立按键:
同理从GND引线通过一个按键开关到单片机I/O口,软件初始化配置为上拉输入或浮空输入。当按键开关按下时开关导通,单片机I/O口就检测到低电平输入。
注意:
实现方式不同的独立按键,按键检测函数也不相同,需要修改到对应的检测方式功能才能正常使用,比如低电平和高电平的检测独立按键,它们的按键检测判断条件是相反的。接入的高电平使用对应STM32单片机GPIO引脚所能承受的最大电压(大多数IO能承受5V,推荐使用3.3V),否则将损坏芯片。
按键控制电路分析
LM401-Pro-Kit评估板上按键部分的原理图如下:

由上图可知,按键连接到PA0,低电平有效,所以按键配置为上拉输入,默认情况下读取到GPIO的电平为高电平,当按键按下时,相关管脚变成低电平。
GPIO控制函数

这里的输入是以MCU为参照而言的,也就是MCU读取指定GPIO端口的数据。

这里的输出也是以MCU为参照的,也就是MCU向指定GPIO端口写入数据。

该函数完成GPIO端口状态0/1的变换,在前一篇文章中有解释。
实现代码
本文的代码是在上文《STM32WL开发之LORA评估板上通过GPIO控制LED》的基础上开发的,LED灯也沿用上文中的LED1,本文主要介绍按键KEY部分的代码,LED 部分的代码就不再赘述。
1、宏定义
- /****** 在stm32wlxx_LM401.h文件中 ******/
-
- typedef enum
-
- {
-
- BUTTON_SW1 = 0, // 按键定义
-
- BUTTON_SW2 = 1,
-
- BUTTON_SW3 = 2,
-
- }Button_TypeDef;
-
-
-
- typedef enum
-
- {
-
- BUTTON_MODE_GPIO = 0,
-
- BUTTON_MODE_EXTI = 1 // 按键采用中断触发方式
-
- }ButtonMode_TypeDef;
-
-
-
- #define BUTTON_SW1_PIN GPIO_PIN_0
-
- #define BUTTON_SW1_GPIO_PORT GPIOA
-
- #define BUTTON_SW1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
-
- #define BUTTON_SW1_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE()
-
- #define BUTTON_SW1_EXTI_LINE EXTI_LINE_0
-
- #ifdef CORE_CM0PLUS
-
- #define BUTTON_SW1_EXTI_IRQn EXTI1_0_IRQn
-
- #else
-
- #define BUTTON_SW1_EXTI_IRQn EXTI0_IRQn
-
- #endif
-
- #define H_EXTI_0 hpb_exti[BUTTON_SW1]
-
-
-
- #define BUTTONx_GPIO_CLK_ENABLE(__INDEX__) do { if ((__INDEX__) == BUTTON_SW1) BUTTON_SW1_GPIO_CLK_ENABLE(); else \
- if ((__INDEX__) == BUTTON_SW2) BUTTON_SW2_GPIO_CLK_ENABLE(); else \
-
- if ((__INDEX__) == BUTTON_SW3) BUTTON_SW3_GPIO_CLK_ENABLE();} while(0)
-
-
-
- #define BUTTONx_GPIO_CLK_DISABLE(__INDEX__) do { if ((__INDEX__) == BUTTON_SW1) BUTTON_SW1_GPIO_CLK_DISABLE(); else \
- if ((__INDEX__) == BUTTON_SW2) BUTTON_SW2_GPIO_CLK_DISABLE(); else \
-
- if ((__INDEX__) == BUTTON_SW3) BUTTON_SW3_GPIO_CLK_DISABLE();} while(0)
2、按键初始化函数
- /***** 在stm32wlxx_LM401.c文件中 *****/
- int32_t BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode)
- {
- GPIO_InitTypeDef gpio_init_structure = {0};
- static BSP_EXTI_LineCallback button_callback[BUTTONn] = {BUTTON_SW1_EXTI_Callback, BUTTON_SW2_EXTI_Callback, BUTTON_SW3_EXTI_Callback};
- static uint32_t button_interrupt_priority[BUTTONn] = {BSP_BUTTON_USER_IT_PRIORITY, BSP_BUTTON_USER_IT_PRIORITY, BSP_BUTTON_USER_IT_PRIORITY};
- static const uint32_t button_exti_line[BUTTONn] = {BUTTON_SW1_EXTI_LINE, BUTTON_SW2_EXTI_LINE, BUTTON_SW3_EXTI_LINE};
-
- /* Enable the BUTTON Clock */
- BUTTONx_GPIO_CLK_ENABLE(Button);
-
- gpio_init_structure.Pin = BUTTON_PIN[Button];
- gpio_init_structure.Pull = GPIO_PULLUP;
- gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH;
-
- if(ButtonMode == BUTTON_MODE_GPIO)
- {
- /* Configure Button pin as input */
- gpio_init_structure.Mode = GPIO_MODE_INPUT;
- HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure);
- }
- else /* (ButtonMode == BUTTON_MODE_EXTI) */
- {
- /* Configure Button pin as input with External interrupt */
- gpio_init_structure.Mode = GPIO_MODE_IT_FALLING; // 按键采用下降沿中断触发的方式
-
- HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); // 按键所用的GPIO初始化
-
- (void)HAL_EXTI_GetHandle(&hpb_exti[Button], button_exti_line[Button]);
- (void)HAL_EXTI_RegisterCallback(&hpb_exti[Button], HAL_EXTI_COMMON_CB_ID, button_callback[Button]);
-
- /* Enable and set Button EXTI Interrupt to the lowest priority */
- HAL_NVIC_SetPriority((BUTTON_IRQn[Button]), button_interrupt_priority[Button], 0x00); // 设置中断优先级
- HAL_NVIC_EnableIRQ((BUTTON_IRQn[Button])); // 启动中断
- }
-
- return BSP_ERROR_NONE;
- }
3、中断处理函数
- /***** 在stm32wlxx_it.c文件中 ****/
- void EXTI0_IRQHandler(void)
- {
- /* USER CODE BEGIN EXTI0_IRQn 0 */
-
- /* USER CODE END EXTI0_IRQn 0 */
- HAL_GPIO_EXTI_IRQHandler(BUT1_Pin); // 调用HAL层的中断处理函数
- /* USER CODE BEGIN EXTI0_IRQn 1 */
-
- /* USER CODE END EXTI0_IRQn 1 */
- }
-
- /**
- * @brief Handle EXTI interrupt request.
- * @param GPIO_Pin Specifies the port pin connected to corresponding EXTI line.
- * @retval None
- */
- void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
- {
- /* EXTI line interrupt detected */
- if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
- {
- __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
- HAL_GPIO_EXTI_Callback(GPIO_Pin);
- }
- }
-
- /***** 在subghz_phy_app.c文件中 *****/
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- {
- switch (GPIO_Pin)
- {
- case BUTTON_SW1_PIN: // 当按键SW1中断触发时
- BSP_LED_On(LED_BLUE) ; // LED1的蓝灯亮
- HAL_Delay(200); // 延迟200ms
- BSP_LED_Off(LED_BLUE) ; // LED1的蓝灯灭
- APP_PRINTF("BUTTON SW1\r\n");
-
- break;
-
- default:
- APP_PRINTF("Unkonw Button\r\n");
- break;
- }
- }
4、主函数
- /***** 在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 */
- /* 定时器初始化 */
- UTIL_TIMER_Init();
-
- /* 初始化LED灯 */
- BSP_LED_Init(LED_BLUE);
-
- /* 初始化按键,指定采用外部中断触发的方式 */
- BSP_PB_Init(BUTTON_SW1, BUTTON_MODE_EXTI);
- /* USER CODE BEGIN 2 */
-
- /* USER CODE END 2 */
-
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
-
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
测试验证
编译工程后下载到LM401-Pro-Kit评估板上,按下PA0按键可看到LED1的蓝灯亮起,符合设计预期。
工程代码下载:
链接: https://pan.baidu.com/s/1MpVU_UDMYITYdjSG7bccqA
提取码: iyrz