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

如何基于STM32F407 Discovery计算按键按压时长?

STM32F407按键按压时长检测实现方案

核心思路

用32位定时器实现高精度计时,主循环采用非阻塞逻辑处理LED闪烁,通过检测按键的按下/松开状态变化记录并计算按压时长,松开按键后根据时长阈值执行对应LED闪烁周期调整。

硬件配置

  • 按键:PA0(开发板USER按键)、PB0,配置为上拉输入(按键按下时接地)
  • LED:PD13(开发板LD2),配置为推挽输出
  • 定时器:TIM2,配置为1ms步进计数(适配168MHz系统时钟)

代码实现

1. 定时器初始化(TIM2)

#include "stm32f4xx.h"

void TIM2_Init(void) {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
    // 168MHz时钟 → 预分频167 + 自动重装载999 = 1ms计数一次
    TIM_TimeBaseStructure.TIM_Prescaler = 167;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_Period = 999;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    
    TIM_Cmd(TIM2, ENABLE); // 启动定时器
}

2. GPIO初始化(按键+LED)

void GPIO_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOD, ENABLE);
    
    // 按键PA0、PB0:上拉输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    // LED PD13:推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
}

3. 主循环逻辑(非阻塞处理)

uint8_t key1_pressed = 0; // PA0按键按下标记
uint32_t key1_start_time = 0;
uint8_t key2_pressed = 0; // PB0按键按下标记
uint32_t key2_start_time = 0;
uint32_t led_blink_period = 500; // 默认LED闪烁周期500ms
uint32_t last_led_toggle_time = 0;

int main(void) {
    SystemInit(); // 初始化系统为168MHz
    TIM2_Init();
    GPIO_Init();
    
    while(1) {
        // 非阻塞LED闪烁
        if(TIM_GetCounter(TIM2) - last_led_toggle_time >= led_blink_period) {
            last_led_toggle_time = TIM_GetCounter(TIM2);
            GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
        }
        
        // PA0按键检测(含消抖)
        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == RESET && !key1_pressed) {
            // 10ms消抖,确认按键稳定按下
            uint32_t debounce_start = TIM_GetCounter(TIM2);
            while(TIM_GetCounter(TIM2) - debounce_start < 10);
            if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == RESET) {
                key1_pressed = 1;
                key1_start_time = TIM_GetCounter(TIM2);
            }
        } else if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == SET && key1_pressed) {
            key1_pressed = 0;
            uint32_t press_duration = TIM_GetCounter(TIM2) - key1_start_time;
            // 短按(800-1200ms)、长按(3800-4200ms)阈值
            if(press_duration >= 800 && press_duration <= 1200) {
                led_blink_period = 500;
            } else if(press_duration >= 3800 && press_duration <= 4200) {
                led_blink_period = 2000;
            }
        }
        
        // PB0按键检测(逻辑同PA0,对应不同操作)
        if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == RESET && !key2_pressed) {
            uint32_t debounce_start = TIM_GetCounter(TIM2);
            while(TIM_GetCounter(TIM2) - debounce_start < 10);
            if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == RESET) {
                key2_pressed = 1;
                key2_start_time = TIM_GetCounter(TIM2);
            }
        } else if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == SET && key2_pressed) {
            key2_pressed = 0;
            uint32_t press_duration = TIM_GetCounter(TIM2) - key2_start_time;
            if(press_duration >= 800 && press_duration <= 1200) {
                led_blink_period = 100;
            } else if(press_duration >= 3800 && press_duration <= 4200) {
                led_blink_period = 3000;
            }
        }
    }
}

关键注意事项

  • 按键消抖:添加10ms延迟确认按键状态,避免机械抖动导致的误触发
  • 时钟匹配:若系统时钟不是168MHz,需调整TIM2的预分频和自动重装载值,保证1ms计时步进
  • 非阻塞设计:所有操作均通过定时器计数差值判断,主循环无阻塞,确保按压期间LED持续工作
  • 阈值容错:设置时长容错范围(如短按±200ms),避免按键操作的微小误差导致功能失效

内容的提问来源于stack exchange,提问作者namlı

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 22:35:23