cubemx配置
1.GPIO配置
gpio配置为输入上拉模式
2.定时器配置
定时器定时10ms 开启中断
变量定义
struct keys
{
bool single_flag; //按键按下标志位
bool key_sta; //按键状态
bool long_flag; //长按标志位
bool double_flag; //双击标志位
unsigned char judge_sta; //判断状态
};
struct keys key[5]={0,0,0,0,0};
int long_time; //长按时间
int double_time=0; //双击时间
int click_count=0; //按下次数
主体逻辑
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM4)
{
double_time++; //10ms进行一次计数++
//读取按键状态
key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i=0;i<4;i++) //循环判断
{
switch(key[i].judge_sta)
{
case 0:
if(key[i].key_sta==0) //按键第一次按下
{
long_time=0; //长按时间计数清零
key[i].judge_sta=1; //使得下一次进入中断到case1
if(double_time>30) double_time=0; //双击时间计数清零
}
break;
case 1:
if(key[i].key_sta==0) //消抖
{
key[i].judge_sta=2; //使得下一次进入中断到case2
}
else key[i].judge_sta=0; //第二次未按下视为抖动 回到case0重新判断
break;
case 2:
if(key[i].key_sta==1) //按键松手
{
double_time=0; //双击时间计数清零
click_count++; //按键按下次数加一
key[i].judge_sta=0; //回到case0
}
else //按键未松手进行长按时间计数
{
long_time++;
}
break;
}
if(click_count==1&&long_time>200) //如果按下一次 且按下时间大于2s 视为长按
{
key[i].long_flag=1; //长按标志位置1
click_count=0; //按键按下次数清零
}
else if(click_count==2&&double_time<30)//如果按下2次 且两次按下时间间隔小于300ms视为双击
{
key[i].double_flag=1; //长按标志位值1
click_count=0;
}
else if(click_count==1&&double_time>30&&long_time<200)//如果按下1次 两次按下时间间隔大于300ms且长按时间小于2s 视为单击
{
key[i].single_flag=1;
double_time=0;
click_count=0;
}
}
}
}
个人理解:
双击时间计数值进入中断就+1
只要检测到按下且松手,双击时间计数就清零同时按下的计数+1
检测到按下未松手,长按时间计数+1
在扫描按键之外先判断长按,如果只按下一次,且按下时间大于2s 就视为长按
再判断双击,如果按下次数为2,两次按下的时间间隔(通过双击时间计数值来判断,因为每次按下就会清零,进入中断就会加一)小于300ms 就视为双击
最后判断单击
不足:会影响单击判断时间,使得单击操作延迟300ms 欢迎指正