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

时间:2021-11-19 18:00:15

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

//按键按下去会出现下降沿,设置按键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 更新中断标志
}
}