STM8L 简单按键复用处理(短按、长按)


前言

开发中经常遇到按键数很少,却要实现多种类型触发功能的场合,比如短按、长按、双击等等,即所谓按键复用。一般情况下,都是在中断函数中收到终端,做延时判断、防抖等处理。但中断处理不能太久,所以稍微好一些的实现,基本是用定时器来扫描处理。 关于这个按键复用功能,乐鑫ESP32/ESP8266的一个开源项目esp-iot-solution中,有一个非常精彩的实现,虽然平台不同,大家可以参考思路。 本文描述的是一个简单实现方法,简洁易用。

一、实现原理

  1. 处理按键的上升和下降中断
  2. 设置一分辨率略高的定时器,比如1ms,用于计数自增
  3. 在按键触发(上升或下降)中断到来时,启动定时器
  4. 在按键松开中断到来时,停止定时器,并根据计数情况判断是短按还是长按

二、使用步骤

1.按键中断初始化

代码如下(示例):
具体引脚根据应用替换,这里是PF5,注意优先级设的比较高

void exti_button_key_init(void)
{
	/ Init key pin //
	GPIO_DeInit(GPIOF);
	GPIO_Init(GPIOF, GPIO_Pin_5, GPIO_Mode_In_PU_IT);

	EXTI_SetPortSensitivity(EXTI_Port_F, EXTI_Trigger_Rising|EXTI_Trigger_Falling);
	
	EXTI_SelectPort(EXTI_Port_F);
	EXTI_SetHalfPortSelection(EXTI_HalfPort_F_MSB ,ENABLE);
	EXTI_SetHalfPortSelection(EXTI_HalfPort_F_LSB ,DISABLE);
	ITC_SetSoftwarePriority( EXTIE_F_PVD_IRQn, ITC_PriorityLevel_1);	
}

2.定时器操作

代码如下(示例):
减少其他处理的干扰,中断优先级设的比较高,另外如果无需高精度,可将定时器调整为10ms或更多。

void keyscan_timer_init(void)
{
    CLK_PeripheralClockConfig(CLK_Peripheral_TIM3, ENABLE);
    TIM3_DeInit();

    /* (1/16MHz)*16*1000 = 1ms */
    TIM3_TimeBaseInit(TIM3_Prescaler_16, TIM3_CounterMode_Up, 1000);
    TIM3_ITConfig(TIM3_IT_Update, ENABLE);
    TIM3_ARRPreloadConfig(ENABLE);
    TIM3_SetCounter(0);

    ITC_SetSoftwarePriority(TIM3_UPD_OVF_TRG_BRK_USART3_TX_IRQn , ITC_PriorityLevel_1);
}

void keyscan_timer_start(void)
{
	keyscan_counter = 0;
	TIM3_SetCounter(0);
	TIM3_Cmd(ENABLE);
}

void keyscan_timer_stop(void)
{
		TIM3_Cmd(DISABLE);
}

3. 中断处理

  • 定时器中断处理
 INTERRUPT_HANDLER(TIM3_UPD_OVF_TRG_BRK_USART3_TX_IRQHandler,21)
{
		TIM3_ClearITPendingBit(TIM3_IT_Update);
    	keyscan_counter++;
}
  • 外部中断处理
INTERRUPT_HANDLER(EXTIE_F_PVD_IRQHandler,5)
{
		// 读取状态(判断按下、松开)后清中断
		BitStatus state = GPIO_ReadInputDataBit(GPIOF, GPIO_Pin_5);
		EXTI_ClearITPendingBit(EXTI_IT_PortF);
		
		if( state == RESET ) { // 按下,开始计数(这里是Falling)
			keyscan_timer_start();
			return;            // 返回即可,等待松开中断
		} else { // 松开,停止计数(这里是Rising)
			keyscan_timer_stop();
		}
		
		// 短按判断
		// 示例为超过100ms小于3000ms为短按,否则为长按
		// 调整该值可以调整灵敏度和长按区分
		if( keyscan_counter >= 100 && keyscan_counter < 3000 ) { 
			g_key_press = KEY_SHORT_PRESS; // 其他地方处理按键状态
		}
		
		// 长按判断
		else if( keyscan_counter >= 3000 ) {
			g_key_press = KEY_LONG_PRESS; // // 其他地方处理按键状态
		}
}

总结

  • 上述方案满足基本功能,如果需要支持双击,还需要做额外的工作,这里不再展开
  • 因上述实现方法问题,要按键要松开后才会响应处理,一直长按是不响应的,如果要实现长按即处理,可在定时器中断处理中,根据引脚值自增,并做计数判断即可。

希望对大家有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值