对于单片机的长按短按连击的实现(二长按)

在前面我们讲到单片机的循环消抖的操作实现,这里我们继续实现对于长按的实现,那么我们首先要了解长按的过程

我们都知道在按键按下的时候会有一个抖动的时间,那么抖动结束以后就是真正按下按键的时间,那么这里就实现了按键的消抖,那么如果我们继续按下想要执行长按怎么办?我们依旧是前面消抖的循环思维来接撅着个问题,再定义一个长按标志位来判断是长按还是短按,废话不多说,我们来看代码:

首先,我们先把结构体定义出来,这里我们统一说明一下结构体内部的变量有什么作用:

​
typedef struct{
    uint8_t key_flag : 1;
    uint8_t key_long_flag : 1;
    uint16_t key_out;
    uint8_t key_num;
    uint8_t key_long_num;
}KeyState;


​

1.总标志位key_flag,判断按键有没有按下

2.key_long_flag长按标志位,判断是长按还是短按

3.key_out,计数器,记录时间

4.key_num和key_long_num是按键的键值

 然后我们可以采用枚举的方法枚举键值,也可以宏定义键值

​
#define key1_disp_num  1
#define key2_disp_num  2
#define key3_disp_num  3
#define key1_long_num 11
#define key2_long_num 22
#define key3_long_num 33

​

然后我们将按键的长按时间,消抖时间做一个宏定义

#define KEY_Disp_Time 20
#define KEY_Long_Time 200

这里说一下,因为代码内容的不同,循环时间可能长短不依,这里宏定义就是为了好修改,因为如果单词循环的时间太长,那么这里的长按就需要按下很久才能判断,如果循环一次的时间太短,这里短按就无法被识别到,就会只出现长按的现象,所以根据你自己的需求进行修改

然后我们就进行定义按键了,我们之前提到过模块化编程,所以这里用一个.h文件来包含定义和函数申明:

#ifndef _key_h_
#define _key_h_


#define KEY_Long_Time 100        // 长按时间
#define KEY_Disp_Time 20        // 消抖时间

#define key1_disp_num  1
#define key2_disp_num  2
#define key3_disp_num  3
#define key1_long_num  11
#define key2_long_num  22
#define key3_long_num  33        // 宏定义键值,也可以枚举,枚举的话就要修改返回值

#define KEY1 PAin(0)
#define KEY2 PAin(1)
#define KEY3 PAin(2)            // 定义三个按键

typedef struct{
    uint8_t key_flag : 1;        // 按键按下标志位
    uint8_t key_long_flag : 1;    // 按键长按标志位
    uint16_t key_out;            // 按键计数器
    uint8_t key_num;            // 按键的短按键值
    uint8_t key_long;            // 按键长按键值
}KeyState;

void Key_Init(void);
uint8_t Key_Read_Output(void);

#endif

​

​

首先先把框架搭好,然后定义一个案件识别的结构体,今天这里为了防止形参过多,就用TM32的微带操作来讲解,对于使用51的同学也方便理解,就可以不用使用形参了,然后我们就开始驱动程序的编写了:

 

#include "key.h"

KeyState Key_State[3] = {
            { 0, 0, 0, key1_disp_num, key1_long_num },
            { 0, 0, 0, key2_disp_num, key2_long_num },
            { 0, 0, 0, key3_disp_num, key3_long_num }
};

void Key_Init(void)
{
    /**
    *    这里是STM32的GPIO初始化,我就不进行编写了,51的同学也不用管
    */
}

/**
*    这里对下下面的代码进行说明,为什么使用指针
*    因为指针有空指针的说法,但是没有空结构体的
*    说法,这样可以对没有按键按下时的结构体进行
*    操作
*/

KeyState *Key_Read_Input(void)
{
    if (!KEY1)      return &Key_State[0];
    else if (!KEY2) return &Key_State[1];
    else if (!KEY3) return &Key_State[2];

    return NULL;
}

uint8_t Key_Read_Output(void)
{
    KeyState keystate;
    uint8_t key_num = 0;      // 这里给key_num赋初值,每次进来就是0
    
    keystate = Key_Read_Input()l       // 给指针分配内存
    if (keystate == NULL)              // 当没有按键按下时
    {
        for (uint8_t i = 0; i < 3; ++i)
        {
            Key_State[i].key_out = 0;
            if (Key_State[i].key_flag)        // 判断总标志位是否按下按键
            {
                if (Key_State[i].key_long_flag)        // 判断长按标志位是否是长按
                {
                    key_num = Key_State[i].key_long_num;    // 是长按就给长按键值
                } else {
                    key_num = Key_State[i].key_num;        // 不是长按就是短按
                }
            }
        }
    } else if (!keystate->key_long_flag) {       // 判断是否已经长按,如果是,那么就不再进入
        keystate->key_out++;                // 计数器计数
        if (keystate->key_out == KEY_Disp_Time)
        {
            keystate->key_flag = 1;            // 已经达到消抖时间,证明按键已经按下
        }
        if (keystate->key_out == KEY_Long_Time)
        {
            keystate->key_long_flag = 1;  
        }
    }

    return key_num;        // 返回键值
}
我们简单介绍一下代码,首先我们进入判断,如果没有按键按下,keystate就被赋为空指针,那么我们现在继续看,进入一个for循环,然后进行判断有没有按下,没有就等待下一次循环,如果按下,就对计数器进行++,直到消抖完成,总标志位就会被值1,当长按时间到了就不再进入,直到按键释放

这样就完成了长按的识别。 

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值