You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32F407VG短按长按功能异常求助:仅触发短按

STM32F407VG按键长短按功能排查与修复

我正在用STM32F407VG开发板做产品设计,需要实现按键的短按(控制亮度)和长按(开关显示,时长约2-3秒)功能。目前用板载用户按键、TIM6定时器(每20ms触发一次中断)实现逻辑,但只能触发短按,处理不了长按。已经知道还没加按键防抖,后续会补充。下面是相关代码,帮忙排查问题:

volatile uint32_t buttonPressTime = 0;
volatile uint8_t buttonPressed = 0;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM6_Init(void);

#define SHORT_PRESS_THRESHOLD 50 // 示例:50毫秒
#define LONG_PRESS_THRESHOLD 3000 // 3秒

int main(void)
{
  
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM6_Init();
 
  HAL_TIM_Base_Start_IT(&htim6); // 启用中断启动TIM6
  
  while (1)
  {
      if (buttonPressed) {
          if (buttonPressTime < SHORT_PRESS_THRESHOLD) {
              // 处理短按
              printf("Short Press");
          } else if (buttonPressTime >= LONG_PRESS_THRESHOLD)
          {
              // 处理长按
              printf("Long presss");
          }
          buttonPressed = 0; // 重置标志位
      }
  }
}

TIM6初始化代码

static void MX_TIM6_Init(void)
{
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 55;
  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim6.Init.Period = 59999;
  htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

定时器回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM6)
    {
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
        {
            buttonPressTime++; // 累加按键按下时长计数
        }
        else
        {
            if (buttonPressTime > 0)
            {
                buttonPressed = 1; // 设置按键按下标志位
            }
            buttonPressTime = 0; // 重置时长计数
        }
    }
}

问题根源分析

  1. 时间阈值单位不匹配
    你定义的阈值是毫秒,但buttonPressTime的单位是20ms(TIM6中断周期),不是毫秒。比如长按阈值3000ms对应的计数应该是3000/20=150,当前用3000直接和计数比较,永远达不到触发条件。

  2. 长按触发逻辑缺失
    当前只有按键松开时才会设置buttonPressed标志,长按过程中按键一直按住,主循环永远检测不到长按事件,必须在按键持续按下时主动判断是否达到长按阈值。

  3. 重复触发与逻辑冲突
    长按触发后未及时重置计数,可能导致后续误判;按键松开时如果已经触发过长按,应该避免再触发短按。

修改后的代码示例

主函数调整

volatile uint32_t buttonPressTime = 0;
volatile uint8_t buttonPressed = 0;
volatile uint8_t longPressTriggered = 0; // 新增长按触发标志
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM6_Init(void);

// 调整阈值为20ms的倍数
#define SHORT_PRESS_COUNT 3    // 3*20ms=60ms,接近原50ms需求
#define LONG_PRESS_COUNT 150   // 150*20ms=3000ms,符合长按需求

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM6_Init();
  HAL_TIM_Base_Start_IT(&htim6);

  while (1)
  {
      if (buttonPressed) {
          // 仅在未触发过长按且计数符合短按时,触发短按逻辑
          if (!longPressTriggered && buttonPressTime <= SHORT_PRESS_COUNT) {
              printf("短按触发\n");
          }
          buttonPressed = 0;
          longPressTriggered = 0;
      }
      if (longPressTriggered) {
          // 长按逻辑(如需持续触发可移除标志位重置)
          printf("长按触发\n");
          longPressTriggered = 0;
      }
  }
}

回调函数调整

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM6)
    {
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
        {
            buttonPressTime++;
            // 达到长按阈值且未触发过,设置长按标志
            if (buttonPressTime >= LONG_PRESS_COUNT && !longPressTriggered)
            {
                longPressTriggered = 1;
                buttonPressTime = 0; // 重置计数避免重复触发
            }
        }
        else
        {
            if (buttonPressTime > 0)
            {
                buttonPressed = 1; // 按键松开触发短按检测
            }
            buttonPressTime = 0;
        }
    }
}

额外说明

原TIM6配置的定时周期确实是20ms(基于168MHz系统时钟计算),这部分无需修改。后续添加防抖时,可在回调函数中增加连续多次状态检测逻辑,避免按键抖动导致误触发。

内容的提问来源于stack exchange,提问作者Muhammad Haris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 14:10:14