sssssw
单次响应:
我们在使用stm32的时候,常常会用到按键操作,用按键实现我们逻辑功能。但开发板上的机械按键常常会遇到机械抖动,我们都知道要用到HAL_Delay操作实现按键消抖,但这样在循环中使用延时操作,使单片机在主循环中的运行效率大大下降,不利于程序的运行。所以我们采用定时器的操作实现,按键消抖。
struct keys{
bool key_sta;
bool key_judge_sta;
bool key_single_press;
};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM6)
{
key[0].key_sta = KEY1;
key[1].key_sta = KEY2;
key[2].key_sta = KEY3;
key[3].key_sta = KEY4;
for(int i=0;i<4;i++)
{
switch(key[i].judge_sta)
{
case 0:
if(key[i].key_sta == 0) key[i].judge_sta=1;
break;
case 1:
if(key[i].key_sta == 0) key[i].single_flag = 1, key[i].judge_sta = 0;
break;
}
}
}
}
将定时器设置为10ms的中断,每进入一次循环,都会将四个按键的状态获取一遍,进入for循环,将四个按键的所有状态遍历,当key[1].key_sta=0时,意味着按键被按下,但此时我们并不确定是不是,抖动所致,所以设置了key[1].judge_sta变量,用于判断按键是否在下一个10ms中,是否还为0,如果是,那么key[1].single_sta置1,此次按键被响应。
长按响应:
在使用中,通常会出现,多个不同的响应,而我们的按键数量有限,如果只用单次响应,无法实现一个按键控制多个任务。这里我们想要实现长按响应,顾名思义,它的意思是通过长时间按键控制所要控制的事情。
struct keys{
unsigned char judge_sta;
bool key_sta;
bool single_down_flag;
bool long_flag;
int key_time;
};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM6)
{
key[0].key_sta = KEY1;
key[1].key_sta = KEY2;
key[2].key_sta = KEY3;
key[3].key_sta = KEY4;
for(int i=0;i<4;i++)
{
switch(key[i].judge_sta)
{
case 0:
if(key[i].key_sta == 0) key[i].judge_sta=1;
break;
case 1:
if(key[i].key_sta == 0)
{
key[i].single_down_flag = 1;
key[i].judge_sta = 2;
}
break;
case 2:
if(key[i].key_sta == 1)
{
if(key[i].key_time > 70){key[i].long_flag = 1;}
key[i].key_time = 0;
key[i].judge_sta = 0;
}
else key[i].key_time++;
break;
}
}
}
}
在数组里面,我们定义了key_time和long_flag变量,其中key_time用来计我们按下去的时间,long_flag用来标记我们长按的标志位。在我们按下按键时,首先会进入到case 0 和 case 1,当我们按键未被抬起的时候,则会进入到case 2的else分支,key[i].key_time++。每10ms执行一次。当按键抬起后, 进入if分支后,判断key[i].key_time是否 > 70,如果大于70,则意味着按下的时间大于700ms,我们判断为长按。key[i].long_flag置1。
双击响应:
双击响应的核心在于要记录按下和下次按下的时间,只有两次按下的时间差满足一定条件的时候,双击响应才会触发。
struct keys{
unsigned char judge_sta;
bool key_sta;
bool double_key_flag;
uint32_t key_double_time;
};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM6)
{
key[0].key_sta = KEY1;
key[1].key_sta = KEY2;
key[2].key_sta = KEY3;
key[3].key_sta = KEY4;
for(int i=0;i<4;i++)
{
switch(key[i].judge_sta)
{
case 0:
if(key[i].key_sta == 0) key[i].judge_sta=1;
break;
case 1:
if(key[i].key_sta == 0)
{
key[i].single_down_flag = 1;
key[i].judge_sta = 2;
if(key[i].key_double_time < 30) key[i].double_key_flag= 1;
key[i].key_double_time = 0;
}else key[i].judge_sta = 0;
break;
case 2:
if(key[i].key_sta == 1)
{
key[i].judge_sta = 0;
}
break;
}
key[i].key_double_time++;
}
}
}
我们定义了key_double_time和double_key_flag两个变量,分别用来表示,双击空闲时间和双击是否被触发。 每遍历一次循环,key[i].key_double_time++,每当按键按下的时候,key[i].key_double_time会置为0,如果下次按键按下时,两次的时间间隔不超过300ms,就意味着双击按键被响应,double_key_flag置1。