介绍
按键消抖:使用定时器每10ms的中断来实现消抖,因为按键的抖动查不到在5-10ms之间,所以使用定时器跳过这10ms的抖动
按键的单按键,双击按键和长按键使用定时器轮询4个按键+状态机的方式实现
步骤
①cubemx配置
使用定时器6来实现每10ms轮询4个按键
开启定时器中断
②代码编写
按键结构体的声明
struct key
{
uint8_t keyJudge; //按键状态机的状态
bool keyState; //按键电平状态
bool keySingle; //单击按键
bool keyDouble; //双击按键
bool keyLong; //长按按键
int keyTime; //用于按键计时
bool keyUp; //检测按键抬起的一瞬间,可用于长按抬手盘判断
bool keyDown; //检测按键按下的一瞬间
};
//按键初始化
struct key keys[4] = {{0,1,0,0,0,0,0,0},{0,1,0,0,0,0,0,0},{0,1,0,0,0,0,0,0},{0,1,0,0,0,0,0,0}};
按键状态机编写
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//定时器的中断回调处理函数
{
if(htim->Instance == TIM6)
{
//每10ms获取一次按键状态
keys[0].keyState = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
keys[1].keyState = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
keys[2].keyState = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
keys[3].keyState = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
//使用for循环轮询4个按键
for(int i = 0;i<4;i++)
{
switch(keys[i].keyJudge) //每个按键所处的状态
{
case 0: //按键空闲状态:等待按键按下
{
if(keys[i].keyState==0) //按键按下,进入下一个状态
{
keys[i].keyJudge=1;
}
}
break;
case 1: //按键按下消抖状态
{
if(keys[i].keyState==0) //确认按键按下,进入下一个状态
{
keys[i].keyJudge = 2;
}else{
keys[i].keyJudge = 0; //按键抖动,回到上一个状态
}
}
break;
case 2: //判断是否是长按键
{
if(keys[i].keyState==0)
{
keys[i].keyTime++; //按键按下时,每10ms加1
if(keys[i].keyTime>=100) //按键长按超过1s(10ms*100),确认是长按键
{
keys[i].keyLong = 1;
keys[i].keyJudge=0;
keys[i].keyTime=0;
}
}else{ //按键松手
keys[i].keyJudge=3;
}
}
break;
case 3: //判断是单击还是双击
{
if(keys[i].keyState==1) //如果按键确认松手,进入下一个状态
{
if(keys[i].keyTime<100)
{
keys[i].keyTime=0;
keys[i].keyJudge=4;
}
}else{ //按键抖动,回到上一个状态
keys[i].keyJudge=2;
}
}
break;
case 4: //判断是单击还是双击的状态
{
if(keys[i].keyState==1)
{
keys[i].keyTime++; //按键松手是开始计时
if(keys[i].keyTime>=40) //如果松手超过400ms还没有再次按下按键
{
keys[i].keySingle=1; //单击按键标志位置1
keys[i].keyJudge = 0;
keys[i].keyTime = 0;
}
}else{ //在400ms内检测到按键再次按下,进入下一个状态
keys[i].keyJudge = 5;
}
}
break;
case 5: //按键二次按下消抖
{
if(keys[i].keyState==0)
{
if(keys[i].keyTime<40) //确认是双按键或者长按,进入下一个状态
{
keys[i].keyTime = 0;
keys[i].keyJudge = 6;
}
}else{ //按键抖动,回到上一个状态
keys[i].keyJudge = 4;
}
}
break;
case 6: //按键第二次按下判断是否是长按
{
if(keys[i].keyState==0)
{
keys[i].keyTime++;
if(keys[i].keyTime>=100) //按键按下超过1s,这次按键操作归为长按
{
keys[i].keyLong = 1;
keys[i].keyJudge=0;
keys[i].keyTime=0;
}
}else{ //按键松手
keys[i].keyJudge = 7;
}
}
break;
case 7: //按键松手消抖
{
if(keys[i].keyState==1) //按键确认松手
{
if(keys[i].keyTime<100) //按键不是长按键,则是双击按键
{
keys[i].keyDouble = 1;
}
keys[i].keyJudge = 0;
keys[i].keyTime = 0;
}else{
keys[i].keyJudge = 6;
}
}
break;
}
}
}
}
main函数测试
//main函数测试三个按键模式
if(keys[3].keySingle) //单击,LED1点亮
{
LED1_ON;
keys[3].keySingle = 0;
}
if(keys[3].keyDouble) //双击,LED1熄灭
{
LED1_OFF;
keys[3].keyDouble = 0;
}
if(keys[3].keyLong) //长按,LED1不断翻转
{
LED1_TOGGLE;
keys[3].keyLong = 0;
}