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

微控制器外接按键按压时长检测及对应LED点亮功能实现问询

按键按压时长检测实现方案(PIC/STM32)

实现思路

  • 硬件连接:按键一端接GPIO,另一端接地,GPIO配置为内部上拉(省去额外下拉电阻);LED通过限流电阻接GPIO(GPIO设为推挽输出,可选择低/高电平点亮,根据接线调整)。
  • 消抖处理:机械按键按压/释放时会产生10-20ms的抖动,必须做消抖——新手可以用定时器连续采样(多次状态一致才判定有效),也可以用短延时快速实现,定时器采样更规范。
  • 计时逻辑:用定时器生成1ms固定时间基准,检测到按键按下(消抖后)开始累计计时;按键释放时根据累计时长触发对应LED动作,也可以在按压过程中实时判断时长并点亮LED。
  • 状态管理:用变量记录按键当前状态(按下/释放)、计时起始标志、累计时长,避免重复触发逻辑。

代码示例

STM32(HAL库)

假设使用STM32F103,CubeMX配置:

  • PA0:按键输入,开启内部上拉
  • PA1、PA2:LED输出,推挽模式
  • TIM2:1ms定时中断(预分频71,自动重装载值999,基于72MHz系统时钟)
#include "stm32f1xx_hal.h"

/* 全局变量 */
uint8_t key_state = 0;       // 0:释放,1:按下(已消抖)
uint32_t press_duration = 0; // 按压时长(ms)

/* TIM2中断回调函数 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim->Instance == TIM2)
  {
    if(key_state == 1) // 按键处于按下状态,累计时长
    {
      press_duration++;
    }
  }
}

/* 按键扫描与消抖 */
void Key_Scan(void)
{
  static uint8_t key_buf = 0;
  key_buf = (key_buf << 1) | HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
  
  // 连续8次采样为低电平(上拉模式下按键按下为低),判定有效按下
  if(key_buf == 0x00 && key_state == 0)
  {
    key_state = 1;
    press_duration = 0; // 重置计时
  }
  // 连续8次采样为高电平,判定有效释放
  else if(key_buf == 0xFF && key_state == 1)
  {
    key_state = 0;
    // 根据时长控制LED
    if(press_duration >= 1000 && press_duration < 2000)
    {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    else if(press_duration >= 2000)
    {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
    }
    else // 短按,熄灭所有LED
    {
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
      HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
    }
  }
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM2_Init();
  
  HAL_TIM_Base_Start_IT(&htim2); // 启动定时器中断
  
  while (1)
  {
    Key_Scan();
    HAL_Delay(10); // 扫描间隔,配合消抖采样
  }
}

PIC(XC8编译器,PIC16F877A)

硬件配置:

  • RB0:按键输入,开启内部上拉(通过OPTION_REG配置)
  • RB1、RB2:LED输出(推挽模式)
  • TMR0定时器:1ms定时中断(预分频64,基于4MHz系统时钟,TMR0初始值设为6)
#include <xc.h>

// 配置位(根据PIC型号调整)
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & CP_OFF);

#define _XTAL_FREQ 4000000

/* 全局变量 */
bit key_state = 0;          // 0:释放,1:按下
unsigned int press_duration = 0; // 按压时长(ms)

/* 定时器0中断服务程序 */
void __interrupt() isr(void)
{
  if(T0IF)
  {
    TMR0 = 6; // 重置定时器值,保证1ms中断周期
    T0IF = 0; // 清除中断标志
    
    if(key_state == 1)
    {
      press_duration++;
    }
  }
}

/* 按键扫描与消抖 */
void Key_Scan(void)
{
  static unsigned char key_buf = 0;
  key_buf = (key_buf << 1) | !RB0; // RB0上拉,按下为低,取反后1表示按下
  
  if(key_buf == 0xFF && key_state == 0) // 连续8次采样为按下状态
  {
    key_state = 1;
    press_duration = 0;
  }
  else if(key_buf == 0x00 && key_state == 1) // 连续8次采样为释放状态
  {
    key_state = 0;
    // 根据时长控制LED
    if(press_duration >= 1000 && press_duration < 2000)
    {
      RB1 = 1;
      RB2 = 0;
    }
    else if(press_duration >= 2000)
    {
      RB1 = 1;
      RB2 = 1;
    }
    else
    {
      RB1 = 0;
      RB2 = 0;
    }
  }
}

void main(void)
{
  TRISB0 = 1; // RB0设为输入
  TRISB1 = 0; // RB1设为输出
  TRISB2 = 0; // RB2设为输出
  
  // 配置TMR0定时器
  OPTION_REG = 0b00000110; // 预分频64,TMR0时钟来自Fosc/4
  TMR0 = 6;
  T0IE = 1; // 使能TMR0中断
  GIE = 1;  // 使能全局中断
  
  RB1 = 0;
  RB2 = 0;
  
  while(1)
  {
    Key_Scan();
    __delay_ms(10);
  }
}

内容的提问来源于stack exchange,提问作者Bhaskar Jha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 23:12:38