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

介绍

我们使用的按键都有按键抖动,当按下按键和松开按键都会有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
相关推荐
炸炸鱼.8 小时前
Python 操作 MySQL 数据库
android·数据库·python·adb
Ronaldinho Gaúch8 小时前
MySQL基础
数据库·mysql
不剪发的Tony老师9 小时前
Noir:一款键盘驱动的现代化数据库管理工具
数据库·sql
.柒宇.10 小时前
MySQL双主同步
linux·数据库·mysql·docker
Trouvaille ~10 小时前
【MySQL篇】数据类型:存储数据的基础
android·数据库·mysql·adb·字符集·数据类型·基础入门
一 乐10 小时前
酒店预订|基于springboot + vue酒店预订系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·酒店预订系统
光泽雨11 小时前
UNION 和 UNION ALL 作用
数据库·sql
heimeiyingwang11 小时前
【架构实战】SQL调优实战:从执行计划到索引优化
数据库·sql·架构
恼书:-(空寄12 小时前
分库分表风险应对手册(生产实战版)
数据库·分库分表
XDHCOM12 小时前
ORA-06521: PL/SQL映射函数错误,权威解析Oracle报错故障修复与远程处理方案
数据库·sql·oracle