嵌入式蓝桥杯单按键,双击按键,长按键的实现(含按键消抖)

本文介绍了如何利用定时器6每10ms轮询4个按键,结合状态机设计来处理按键的单击、双击和长按,以及通过Cubemx配置实现消抖功能,确保按键事件的准确性。
摘要由CSDN通过智能技术生成

介绍

          按键消抖:使用定时器每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;
    }

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值