STM32实现按键单击、双击、长按、连按功能,使用状态机,无延时,不阻塞

常见的按键判定程序,如正点原子按键例程,只能判定单击事件,对于双击、长按等的判定逻辑较复杂,且使用main函数循环扫描的方式,容易被阻塞,或按键扫描函数会阻塞其他程序的执行。使用定时器设计状态机可以规避这一问题。

本文在博主 老子姓李! 程序的基础上添加连按功能,整合双击功能并补充双击二次按下消抖,添加可调消抖时间,添加长按、连按、双击使能,扩展一个按键为多按键,修改在定时器运行状态机,在主函数判断,精简部分代码,并添加大量注释方便阅读。
参考博主文章【源码详解-按键状态机-简洁易懂】1.单个按键实现短按长按的功能(基于STM32)

功能介绍

本程序功能:
使用定时器状态机实现按键单击、双击、长按、连按功能。消抖时间可调,长按时间可调,双击判定时间可调,连按单击间隔可调,可选择使能长按、连按、双击功能,无延时不阻塞,稳定触发。移植只需修改读IO函数,结构体初始化和宏定义时间参数即可。

注:

  1. 在定时器状态机判定产生事件标志,在主函数处理并清除事件标志。
  2. 单击是最基本事件,除以下情况外,经过消抖后,在按键释放时触发单击事件。
  3. 使能长按后,若按键按下时间大于长按判定时间,则释放时触发长按事件,若不使能,释放时触发单击事件。
  4. 使能连按后,按住按键时持续触发连按事件,可自定义等效为单击事件。无论是否使能长按,按键长按不释放,先经过长按判定时间触发第一次连按事件,然后循环进行连按计时,每次计时结束后都会触发一次连按事件,直到按键释放,触发长按事件(使能长按),或单击事件(不使能长按)。
  5. 使能双击后,若两次单击行为之间,由释放到按下的时间小于双击判定时间,则第一次单击行为释放时不触发单击事件,第二次单击行为在释放时触发双击事件。一次单击行为在双击判定时间内无按键按下动作,之后才触发单击事件。无论是否使能长按,若上述第二次行为是长按,则第二次释放时不会触发双击事件,而是到达长按判定时间后先触发属于第一次的单击事件,然后在第二次释放按键时触发长按事件(使能长按),或单击事件(不使能长按)。

代码

头文件 my_key.h

#ifndef ___MY_KEY_H__
#define ___MY_KEY_H__
#include "main.h"
#define ARR_LEN(arr) ((sizeof(arr)) / (sizeof(arr[0]))) //数组大小宏函数

#define KEY_DEBOUNCE_TIME 10      //消抖时间
#define KEY_LONG_PRESS_TIME 500   //长按判定时间
#define KEY_QUICK_CLICK_TIME 100  //连按时间间隔
#define KEY_DOUBLE_CLICK_TIME 200 //双击判定时间
#define KEY_PRESSED_LEVEL 0 //按键被按下时的电平

//按键动作
typedef enum
{
   
   
  KEY_Action_Press,   //按住
  KEY_Action_Release, //松开
} KEY_Action_TypeDef;

//按键状态
typedef enum
{
   
   
  KEY_Status_Idle,             //空闲
  KEY_Status_Debounce,         //消抖
  KEY_Status_ConfirmPress,     //确认按下
  KEY_Status_ConfirmPressLong, //确认长按
  KEY_Status_WaitSecondPress,  //等待再次按下
  KEY_Status_SecondDebounce,   //再次消抖
  KEY_Status_SecondPress,      //再次按下
} KEY_Status_TypeDef;

//按键事件
typedef enum
{
   
   
  KEY_Event_Null,        //空事件
  KEY_Event_SingleClick, //单击
  KEY_Event_LongPress,   //长按
  KEY_Event_QuickClick,  //连击
  KEY_Event_DoubleClick, //双击
} KEY_Event_TypeDef;

//按键模式使能选择
typedef enum
{
   
   
  KEY_Mode_OnlySinge = 0x00,         //只有单击
  KEY_Mode_Long = 0x01,              //单击长按
  KEY_Mode_Quick = 0x02,             //单击连按
  KEY_Mode_Long_Quick = 0x03,        //单击长按连按
  KEY_Mode_Double = 0x04,            //单击双击
  KEY_Mode_Long_Double = 0x05,       //单击长按双击
  KEY_Mode_Quick_Double = 0x06,      //单击连按双击
  KEY_Mode_Long_Quick_Double = 0x07, //单击长按连按双击
} KEY_Mode_TypeDef;

//按键配置
typedef struct
{
   
   
  uint8_t KEY_Label;             //按键标号
  KEY_Mode_TypeDef KEY_Mode;              //按键模式
  uint16_t KEY_Count;            //按键按下计时
  KEY_Action_TypeDef KEY_Action; //按键动作,按下或释放
  KEY_Status_TypeDef KEY_Status; //按键状态
  KEY_Event_TypeDef KEY_Event;   //按键事件
} KEY_Configure_TypeDef;

extern KEY_Configure_TypeDef KeyConfig[];
extern KEY_Event_TypeDef key_event[];

void KEY_ReadStateMachine(KEY_Configure_TypeDef *KeyCfg);

#endif

源文件 my_key.c

#include "my_key.h"

static uint8_t KEY_ReadPin(uint8_t key_label)
{
   
   
  switch (key_label)
  {
   
   
  case 0:
    return 
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值