非阻塞按键(单击,双击,长按)

介绍

我们使用的按键都有按键抖动,当按下按键和松开按键都会有20ms的抖动,如果不处理这40ms的抖动,很影响单片机正常读取数据,平时我们都用while循环死等这40ms的抖动,在这40ms内单片机不会运行其他程序,这样很浪费单片机性能,在那些实时性要求不高的项目用while消抖不会影响程序正常运行,但在那些要求实时性很高的项目用while消抖显然不行,所以出现了中断扫描消抖

中断扫描消抖原理

我们用一个每1ms进入一次中断的定时器来进行按键消抖,我们用软件实现在中断中每20ms判断一次按键的状态是否改变,如果改变就进行相应的操作

单击,双击,长按原理

当检查到按键按下,我们开始计时(长按时间阈值),并等待按键松开,如果按键到我们规定的(长按时间阈值)时间都没有松开,这时就判断为长按,如果按键到我们规定的(长按时间阈值)时间之前松开按键时这时就有两种可能

  1. 单击
  2. 双击

单击:当按键到我们规定的(长按时间阈值)时间之前松开按键时,我们继续计时(双击时间阈值),当按键到我们规定的(双击时间阈值)时间都没有按下时,这时我们判断按键为单击 ,当按键到我们规定的(双击时间阈值)时间按下时我们判断按键为双击,

代码思维

代码

复制代码
#include "KEY.h"


static uint8_t KEY_Flag=0;


uint8_t KEY_Check(uint8_t flag)
{
    if(KEY_Flag&flag)
    {
        if (flag!=KEY_HOLD)
        {
         KEY_Flag&=~flag;
        }
        return 1;
    }
    return 0;
}



 
uint8_t KEY_State(void)
{
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_4)==KEY_OK)
    {
        return KEY_OK;
    }
    else
    {
        return KEY_NO;
    }
}

void TIM_Tick(void)
{
    static uint8_t Count;
    static uint8_t CurrState=KEY_NO,PrevState=KEY_NO;
    static uint8_t S;
    static uint16_t NUM;
    if (NUM>0)
    {
        NUM--;
    }
  
    Count++;
    if(Count>=20)
    {
        Count=0;
        PrevState=CurrState;
        CurrState=KEY_State();
        //一直按住
        if(CurrState==KEY_OK)
        {
            KEY_Flag|=KEY_HOLD;
        }
        else
        {
            KEY_Flag&=~KEY_HOLD;
        }
        //按下瞬间
        if(CurrState==KEY_OK&&PrevState==KEY_NO)
        {
            KEY_Flag|=KEY_DOWN;
        }
        //松开瞬间
        if(CurrState==KEY_NO&&PrevState==KEY_OK)
        {
            KEY_Flag|=KEY_UP;
        }
        switch (S)
        {
        case 0:
        //判断按键是否按下
            if(CurrState==KEY_OK)
            {
                //按下S置1
                S=1;
                //并开始记时间,如果2秒后按键还没有松开,按键长按
                NUM=KEY_TIME_LONG;
            }
            break;

        case 1:
        //按键松开
            if(CurrState==KEY_NO)
            {
                //S置2
                S=2;
                //此时按键已经松开,不可能是长按,记时,如果在200ms内再次按下,就是双击
                NUM=KEY_TIME_DOUBLE;
            }
            //按键未松开
            else if (NUM==0)
            {
                //S置4
                S=4;
                //计时判断是一直长按还是普通长按,如果在100ms后还没松开就是一直长按
                NUM=KEY_TIME_LONGLONG;
            }
    
            break;

        case 2:
        //按键按下,双击
            if(CurrState==KEY_OK)
            {
                //双击,S置3,在S=3中将S置0
                KEY_Flag|=KEY_DOUBLE;
                S=3;
            }
        //按键未按下,单击
           else if(NUM==0)
            {
                //单击,将S置0
                KEY_Flag|=KEY_SINGLE;
                S=0;
            }
            break;
        case 3:
            //双击,将S置0
            if(CurrState==KEY_NO)
            {
                S=0;
            }
            break;
        case 4:
        //按键松开,长按
            if(CurrState==KEY_NO)
            {
                //长按
                KEY_Flag|=KEY_LONG;
                S=0;
            }
        //按键未松开,一直长按,
            else if (NUM==0)
            {
               //一直长按
               KEY_Flag|=KEY_LONG_LONG;
            }
            break;
    
        }
    }
}



void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim==&htim2)
    {
        TIM_Tick();
    }

}

#ifndef __KEY_H__
#define __KEY_H__

#include "main.h"
#include "tim.h"

#define KEY_OK 0
#define KEY_NO 1

 //按住不放
#define KEY_HOLD 0X01
//按下瞬间
#define KEY_DOWN 0X02
//松开瞬间
#define KEY_UP   0X04
//单击
#define KEY_SINGLE   0X08
//双击
#define KEY_DOUBLE   0X10
//长按
#define KEY_LONG     0X20
//一直长按
#define KEY_LONG_LONG   0X40

#define KEY_TIME_DOUBLE   200
#define KEY_TIME_LONG     1000
#define KEY_TIME_LONGLONG 100

uint8_t KEY_State(void);

uint8_t KEY_Check(uint8_t flag);

#endif
相关推荐
2401_831824963 小时前
为你的Python脚本添加图形界面(GUI)
jvm·数据库·python
久违的太阳3 小时前
记录一次ORACLE RAC安装PSU补丁步骤
数据库·oracle
2401_879693873 小时前
用Pygame开发你的第一个小游戏
jvm·数据库·python
xushichao19893 小时前
实战:用OpenCV和Python进行人脸识别
jvm·数据库·python
sthnyph4 小时前
初识MySQL · 库的操作
数据库·mysql
原来是猿4 小时前
MySQL【视图】
数据库·mysql
2401_873587824 小时前
MySQL——事务管理
数据库·mysql
探索宇宙真理.4 小时前
SiYuan SQL漏洞 | CVE-2026-29073复现&研究
数据库·经验分享·sql·eureka·安全漏洞·siyuan
2501_945423544 小时前
工具、测试与部署
jvm·数据库·python