前言:在前一篇《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