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

【第3期】按键外部中断调试完成
【mqtt参数上云和小程序开发】
按键1 控制开灯
按键2 控制关灯
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

好的,下面我将为你提供一个完整的STM32按键外部中断控制实例。我们将实现一个常见的功能:通过按键控制LED灯的开关,并且实现按下一次按键,LED状态翻转一次


项目概述

  • 硬件:
    • STM32开发板(以STM32F103C8T6为例)
    • 一个按键(连接至PB11,使用外部中断)
    • 一个LED灯(连接至PC13,这是很多最小系统板自带的LED)
  • 软件:
    • STM32CubeIDE
    • HAL库
  • 功能:
    • 每次按下按键,LED的状态就翻转一次(亮变灭,灭变亮)。
    • 使用外部中断检测按键,响应迅速,不占用主循环资源。

方法一:使用STM32CubeMX图形化配置(最推荐)

步骤1:创建工程并配置时钟和调试
  1. 打开STM32CubeIDE,新建工程,选择你的MCU型号。
  2. Pinout & Configuration 视图:
    • System Core > SYS: Debug 设为 Serial Wire
    • System Core > RCC: HSE 设为 Crystal/Ceramic Resonator
步骤2:配置LED引脚(PC13)
  1. 在芯片图上找到 PC13 引脚,点击选择 GPIO_Output
  2. 在左侧 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
步骤3:配置按键引脚(PB11)为外部中断
  1. 在芯片图上找到 PB11 引脚,点击选择 GPIO_EXTI11
  2. 在左侧 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
步骤4:配置NVIC(使能中断)
  1. 在左侧 System Core > NVIC 中:
  2. 找到并勾选 EXTI line[15:10] interruptsEnabled 复选框。
  3. 优先级可以保持默认。
步骤5:生成代码
  1. 点击 Project Manager,设置项目名称和路径。
  2. 点击 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----+

程序执行流程

  1. 初始化:系统启动,配置PB11为下拉输入的外部中断模式,PC13为推挽输出。
  2. 等待中断:主循环空转,等待按键中断。
  3. 按键按下:按键被按下,PB11从高电平变为低电平,产生下降沿中断。
  4. 进入中断:CPU跳转到EXTI15_10_IRQHandler,最终调用 HAL_GPIO_EXTI_Callback
  5. 设置标志:在回调函数中设置 button_pressed_flag = 1
  6. 主循环检测:主循环检测到 button_pressed_flag 被置位。
  7. 执行动作:主循环清除标志位,并翻转LED的状态。
  8. 等待下一次按键

常见问题及调试技巧

  1. 按键无反应

    • 检查硬件连接是否正确,确保按键一端接PB11,另一端接GND。
    • 用万用表测量按键按下时PB11的电压是否确实被拉低。
    • 检查CubeMX中GPIO配置是否正确(模式、上下拉、触发边沿)。
    • 确认NVIC中已使能EXTI中断。
  2. 按键一次,LED状态变化多次(连击)

    • 这是按键抖动导致的,需要更好的消抖处理。延长消抖时间或使用上述的优化消抖方法。
  3. LED状态与预期相反

    • 检查LED的硬件连接方式(是低电平点亮还是高电平点亮),调整初始输出电平。
  4. 使用仿真器调试

    • 可以在回调函数和主循环的处理部分设置断点,观察程序执行流程。
    • 查看变量 button_pressed_flag 的变化。

这个实例涵盖了STM32按键外部中断的核心知识点,你可以在此基础上扩展更复杂的功能,如长短按检测、双击识别等。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值