STM32学习笔记:单片机按键单击、双击、长按功能实现

  • Post author:
  • Post category:其他


由于项目产品的需要,只能设置一个按键,但是需要实现短按(即单击)切换工作模式、长按开关机、双击暂停等复用功能。下图是三种情况下的按键波形。按键未按下时是高电平,按下去是低电平。按键单击时,判断时间门槛设置为50~2000ms;长按门槛为持续按下2000ms。双击可以视为时间间隔很短的俩次有效单击,从第一次单击上升沿到第二次单击上升沿延时门槛为100~500ms。


这里写图片描述

//按键按下去会出现下降沿,设置按键IO口所在的外部端口为下降沿触发中断。
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
KEY_Init(); //①按键端口初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //②开启 AFIO 时钟
                                                    //GPIOE.2 中断线以及中断初始化配置,下降沿触发
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);//③
EXTI_InitStructure.EXTI_Line=EXTI_Line2;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //④初始化中断线参数

NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能按键外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);//⑤初始化 NVIC
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21



中断服务函数

//⑥外部中断 2 服务程序
void EXTI2_IRQHandler(void)
{
    if(GPIO_ReadInputPin(GPIOE,GPIO_PIN_2)==0) //按键 KEY2
    {
        key_fall_flag = 1;//生成按键按下标志
    }
    EXTI_ClearITPendingBit(EXTI_Line2); //清除 LINE2 上的中断标志位
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9



1ms定时器中断服务函数

void TIM3_IRQHandler(void) //TIM3 中断
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查 TIM3 更新中断发生与否
    {
        if(key_fall_flag==1)//发生按键按下事件
        {
            if(GPIO_ReadInputPin(GPIOB,GPIO_PIN_4)==0)//按键持续按下
             {         
                if(key_holdon_ms <= 2000)  
                 {
                    key_holdon_ms++; 
                 } 
                 else //按键按下到2000ms就判断长按时间成立,生成长按标志 
                 { 
                   key_holdon_ms = 0; 
                   short_key_flag=0;//清短按键标志
                   key_long_down = 1//长按键标志置位
                   key_fall_flag = 0//清按键按下标志 
                  } 
             } 
          else //按键抬起
          { 
               if(key_holdon_ms>50)//按下时间大于50ms,生成单击标志
                {  
                   key_holdon_ms=0;
                   short_key_flag=1;
                   key_long_down =0;
                   key_fall_flag=0;

             //距离上次单击时间在100~500ms之间,则认为发生连击事件
                  if(keyupCnt>100 && keyupCnt<500)
                  { 
                       doubleClick = TRUE;
                       short_key_flag=0;
                  } 
                  keyUpFlag = TRUE;//单击抬起按键后,生成按键抬起标志 
                } 
               else  //按键持续时间小于50ms,忽略 
                  {    
                       key_holdon_ms=0; 
                       short_key_flag=0;
                       long_key_flag=0;
                        key_fall_flag=0;
                 } 
          }

        }
    if(keyUpFlag)//单击抬起后,启动计数,计数到500ms  
         keyupCnt++;
    if(keyupCnt>500)
      { 
          keyupCnt = 0;
          keyUpFlag = FALSE;
      }

    }

        TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除 TIM3 更新中断标志
    }
}