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

介绍

我们使用的按键都有按键抖动,当按下按键和松开按键都会有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
相关推荐
AI-好学者13 小时前
阶段一-图数据库基础与PropertyGraph模型
数据库·rag·knowledge graph·graphrag
其实防守也摸鱼14 小时前
运维--学习阶段问题解答(1)(自测)
linux·运维·服务器·数据库·学习·自动化·命令模式
懒鸟一枚14 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
龙仔72514 小时前
SQL Server 创建只读账号完整操作(分两种场景:SSMS图形界面 + T-SQL脚本)
数据库·sql·oracle
霁月的小屋15 小时前
生产环境中的事务实践——银行系统上线记(四)
数据库
Database_Cool_15 小时前
AI 应用数据底座首选:阿里云 PolarDB 为大模型 RAG 提供一体化支撑
数据库·阿里云
玖玥拾15 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
IvorySQL16 小时前
PG 日报|社区讨论重构 pg_hba 配置文件格式
数据库·人工智能·postgresql·重构·ivorysql
逝水无殇16 小时前
C# 文件的输入与输出详解
开发语言·数据库·后端·c#
罗政18 小时前
PDF 批量合并工具:本地 AI 自动排序、识别正文日期与合同编号
数据库·pdf·php