【第3期】按键外部中断调试完成
【mqtt参数上云和小程序开发】
按键1 控制开灯
按键2 控制关灯



好的,下面我将为你提供一个完整的STM32按键外部中断控制实例。我们将实现一个常见的功能:通过按键控制LED灯的开关,并且实现按下一次按键,LED状态翻转一次。
项目概述
- 硬件:
- STM32开发板(以STM32F103C8T6为例)
- 一个按键(连接至PB11,使用外部中断)
- 一个LED灯(连接至PC13,这是很多最小系统板自带的LED)
- 软件:
- STM32CubeIDE
- HAL库
- 功能:
- 每次按下按键,LED的状态就翻转一次(亮变灭,灭变亮)。
- 使用外部中断检测按键,响应迅速,不占用主循环资源。
方法一:使用STM32CubeMX图形化配置(最推荐)
步骤1:创建工程并配置时钟和调试
- 打开STM32CubeIDE,新建工程,选择你的MCU型号。
- 在 Pinout & Configuration 视图:
- System Core > SYS:
Debug设为Serial Wire。 - System Core > RCC:
HSE设为Crystal/Ceramic Resonator。
- System Core > SYS:
步骤2:配置LED引脚(PC13)
- 在芯片图上找到 PC13 引脚,点击选择 GPIO_Output。
- 在左侧 System Core > GPIO 中,点击 PC13 进行配置:
- GPIO output level:
High(因为LED通常是低电平点亮,初始设为高使其熄灭) - GPIO mode:
Output Push Pull - GPIO Pull-up/Pull-down:
No pull-up and no pull-down - Maximum output speed:
Low - User Label:
USER_LED
- GPIO output level:
步骤3:配置按键引脚(PB11)为外部中断
- 在芯片图上找到 PB11 引脚,点击选择 GPIO_EXTI11。
- 在左侧 System Core > GPIO 中,点击 PB11 进行配置:
- GPIO mode:
External Interrupt Mode with Falling edge trigger detection- 选择下降沿触发是因为:按键通常一端接地,另一端接引脚。当按键未按下时,我们通过上拉电阻使引脚为高电平;按下时,引脚被拉低,产生一个下降沿。
- GPIO Pull-up/Pull-down:
Pull-up(使用内部上拉电阻,这样按键未按下时引脚就是高电平) - User Label:
USER_BUTTON
- GPIO mode:
步骤4:配置NVIC(使能中断)
- 在左侧 System Core > NVIC 中:
- 找到并勾选 EXTI line[15:10] interrupts 的
Enabled复选框。 - 优先级可以保持默认。
步骤5:生成代码
- 点击 Project Manager,设置项目名称和路径。
- 点击 GENERATE CODE。
步骤6:编写用户代码
STM32CubeMX已经帮我们生成了GPIO和NVIC的初始化代码,我们只需要在合适的地方添加应用逻辑。
1. 在 main.c 中定义全局变量和重写回调函数
/* USER CODE BEGIN PV */
// 定义一个 volatile 变量作为中断标志位,用于在中断和主循环之间通信
volatile uint8_t button_pressed_flag = 0;
/* USER CODE END PV */
/*-------------------------------------------------------------------*/
/* USER CODE BEGIN 4 */
/**
* @brief 外部中断回调函数
* @param GPIO_Pin: 触发中断的引脚号
* @retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
// 判断是否是我们的按键引脚(PB11)触发的中断
if (GPIO_Pin == USER_BUTTON_Pin) // USER_BUTTON_Pin 是CubeMX根据User Label自动生成的
{
// 简单的软件消抖:检查一段时间内引脚是否保持稳定
// 这里使用HAL_Delay进行简单消抖,在实际产品中建议用定时器做更精确的消抖
HAL_Delay(10); // 延迟10ms
// 再次检查引脚电平,确认按键确实被按下了(仍然是低电平)
if (HAL_GPIO_ReadPin(USER_BUTTON_GPIO_Port, USER_BUTTON_Pin) == GPIO_PIN_RESET)
{
// 设置按键按下标志位
button_pressed_flag = 1;
}
}
}
/* USER CODE END 4 */
注意: 在中断回调函数中使用 HAL_Delay() 是不推荐的做法,因为它会阻塞整个系统。这里只是为了演示简单。最佳实践是使用定时器进行硬件消抖,或者在主循环中处理消抖。
2. 在主循环中处理按键事件
/* USER CODE BEGIN WHILE */
while (1)
{
// 检查按键按下标志位
if (button_pressed_flag)
{
button_pressed_flag = 0; // 清除标志位
// 执行按键处理逻辑:翻转LED状态
HAL_GPIO_TogglePin(USER_LED_GPIO_Port, USER_LED_Pin);
// 可以在这里添加其他按键按下后要执行的操作
// 例如:发送串口消息、改变模式等
}
// 这里可以执行其他任务,不会被按键检测阻塞
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
方法二:更优化的消抖方式(推荐)
为了避免在中断中使用 HAL_Delay,我们可以采用 “二次检测法”,将消抖逻辑放在主循环中。
修改后的代码:
在 main.c 中:
/* USER CODE BEGIN PV */
// 用于按键消抖的变量
volatile uint8_t button_pressed_flag = 0;
uint32_t button_last_press_time = 0;
#define DEBOUNCE_DELAY_MS 20 // 消抖时间20ms
/* USER CODE END PV */
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == USER_BUTTON_Pin)
{
// 不在这里消抖,只设置标志位和时间戳
button_pressed_flag = 1;
button_last_press_time = HAL_GetTick(); // 记录当前时间戳
}
}
/* USER CODE END 4 */
/* 在主循环中 */
while (1)
{
// 检查按键按下标志位,并且确保已经过了消抖时间
if (button_pressed_flag && (HAL_GetTick() - button_last_press_time) > DEBOUNCE_DELAY_MS)
{
button_pressed_flag = 0; // 清除标志位
// 再次确认按键状态,实现消抖
if (HAL_GPIO_ReadPin(USER_BUTTON_GPIO_Port, USER_BUTTON_Pin) == GPIO_PIN_RESET)
{
// 翻转LED
HAL_GPIO_TogglePin(USER_LED_GPIO_Port, USER_LED_Pin);
}
}
// 其他任务...
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
硬件连接
- LED(PC13):大部分STM32最小系统板已经将PC13连接到了一个LED上。如果没有,请将一个LED串联一个220Ω-1kΩ的电阻连接到PC13和GND之间。
- 按键(PB11):
- 将按键的一个引脚连接到 PB11。
- 将按键的另一个引脚连接到 GND。
- 注意:我们在软件中配置了内部上拉电阻,所以不需要外部上拉电阻。如果你使用外部上拉电阻,GPIO配置中的Pull-up/Pull-down应设为
No pull-up and no pull-down。
3V3
|
|
PB11 o---+
|
=== 按键
|
GND o----+
程序执行流程
- 初始化:系统启动,配置PB11为下拉输入的外部中断模式,PC13为推挽输出。
- 等待中断:主循环空转,等待按键中断。
- 按键按下:按键被按下,PB11从高电平变为低电平,产生下降沿中断。
- 进入中断:CPU跳转到EXTI15_10_IRQHandler,最终调用
HAL_GPIO_EXTI_Callback。 - 设置标志:在回调函数中设置
button_pressed_flag = 1。 - 主循环检测:主循环检测到
button_pressed_flag被置位。 - 执行动作:主循环清除标志位,并翻转LED的状态。
- 等待下一次按键。
常见问题及调试技巧
-
按键无反应:
- 检查硬件连接是否正确,确保按键一端接PB11,另一端接GND。
- 用万用表测量按键按下时PB11的电压是否确实被拉低。
- 检查CubeMX中GPIO配置是否正确(模式、上下拉、触发边沿)。
- 确认NVIC中已使能EXTI中断。
-
按键一次,LED状态变化多次(连击):
- 这是按键抖动导致的,需要更好的消抖处理。延长消抖时间或使用上述的优化消抖方法。
-
LED状态与预期相反:
- 检查LED的硬件连接方式(是低电平点亮还是高电平点亮),调整初始输出电平。
-
使用仿真器调试:
- 可以在回调函数和主循环的处理部分设置断点,观察程序执行流程。
- 查看变量
button_pressed_flag的变化。
这个实例涵盖了STM32按键外部中断的核心知识点,你可以在此基础上扩展更复杂的功能,如长短按检测、双击识别等。
1万+

被折叠的 条评论
为什么被折叠?



