stm32 设计一个按键驱动,可以检测单机,连击,长按等操作

stm32 设计一个按键驱动,可以检测单机,连击,长按等操作


1.期望:

设计一个通用驱动代码:

  • 不需要外部中断
  • 不限制于stm32,可以快速移植到各种单片机(只需要修改一句话)
  • 可以轻松识别单机,连击,长按
  • 不需要堵塞延时,写在主函数也不会堵塞其它代码执行
  • 代码尽量多次分层,减少计算量,写在中断也不会占用过长时间
  • 使用宏定义,可以快速更改时间间隔
  • 软件完美消抖,减少硬件电路设计

2.实现效果:

stm32按键驱动


https://www.bilibili.com/video/BV1G34y1t7CA/

3.先来看驱动代码

使用宏定义,可以快速更改成想要的时间和方便移植

gkey.h

#ifndef GKEY_H__
#define GKEY_H__

#include "main.h"

#define ERROR_TOUCH_T 50 //误触时间(消抖)
#define SINGLE_TOUCH_T 800 //单机最长事件,大于此数值会认为长按
#define CONTINUE_INTERVAL_T 500//连击间隔时间
#define GetSysTimeMs() HAL_GetTick() //获取当前系统时间(ms)
#define retSta_SinglePush   0x01 //单次按下,sta变成的值
//...... 后面的连击会在retSta_SinglePush基础下累加,例如五连击会是retSta_SinglePush+4
#define retSta_LongPush     0xFF //长按,sta变成的值

//按键
class KEY
{
public:
  KEY(bool keypush,uint8_t (*Callback)())
  {
    keyPush=keypush;
    keyReadFun=Callback;
  }
  void keyScan(void);

public:
  uint8_t sta;//实际输出状态
private:
  bool keyPush;//按键按下后会是啥样
  uint8_t (*keyReadFun)();//函数变量keyReadFun
};

#endif //GKEY_H__

gkey.cpp

#include "gkey.h"

void KEY::keyScan(void)
{
    //定义相关变量
    static uint8_t trigFlag;
    static uint8_t waitRelease;
    static long key_trig_t;
    static long lastSingle_trig_t;

    uint8_t keySta=keyReadFun();//读取当前电平

    if(waitRelease==1)//等待释放按键,长按时使用
    {
        if(keySta==keyPush) {sta=0;return;}
        waitRelease=0;
    }

    if(keySta==keyPush)//按键处于按下状态
    {
        if(trigFlag==0)
        {
            trigFlag=1;//触发按键按下
            key_trig_t=GetSysTimeMs();//获取第一次按下时间
        }
        else if(trigFlag==1)//按键已经按下,再次触发中断了
        {
            long intervalT=GetSysTimeMs()-key_trig_t;
            if(intervalT<=ERROR_TOUCH_T) return;//消抖
            else if(intervalT>=SINGLE_TOUCH_T)//长按
            {
                trigFlag=0;//清空标志位
                waitRelease=1;//等待释放按键
                sta=retSta_LongPush;//长按
            }
        }
    }else
    {
        if(trigFlag==0) {sta=0;return;}//按键没有按下,本身也没有触发事件,直接返回
        else //按键虽然没按下,但事件处于被触发状态
        {
            long intervalT=GetSysTimeMs()-key_trig_t;
            if(intervalT<=ERROR_TOUCH_T) {sta=0;return;}//消抖
            else if(intervalT<=SINGLE_TOUCH_T)
            {
                static uint8_t trigCnt;//触发次数记录,用来记录多次连击
                if(GetSysTimeMs()-lastSingle_trig_t<=CONTINUE_INTERVAL_T)//两次单机之间小于一定时间,认定为双击
                {
                    trigCnt++;
                    sta=retSta_SinglePush+trigCnt;//双击
                }else//仍为单机事件
                {
                    trigCnt=0;
                    sta=retSta_SinglePush;//单机
                }
                trigFlag=0;//清除标志位
                lastSingle_trig_t=GetSysTimeMs();//记录上次单次按下事件
            }
        }
    }
}

4.使用示例

定义在全局

uint8_t keyRead(void)
{
	//用户需要修改的地方,方便移植,只需要更改return后面的函数,读取电平函数
	return HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_15);
}
//初始化按键,第一个参数是按下后按键的电平,第二个是上面的函数名
KEY mykey(0,keyRead);

使用在1000hz处

mykey.keyScan();
if(mykey.sta!=0)
gDebug()<<mykey.sta<<endl;//这里是打印输出,效果就是printf,你们改成自己的
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值