在前面我们讲到单片机的循环消抖的操作实现,这里我们继续实现对于长按的实现,那么我们首先要了解长按的过程
我们都知道在按键按下的时候会有一个抖动的时间,那么抖动结束以后就是真正按下按键的时间,那么这里就实现了按键的消抖,那么如果我们继续按下想要执行长按怎么办?我们依旧是前面消抖的循环思维来接撅着个问题,再定义一个长按标志位来判断是长按还是短按,废话不多说,我们来看代码:
首先,我们先把结构体定义出来,这里我们统一说明一下结构体内部的变量有什么作用:
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,当长按时间到了就不再进入,直到按键释放
这样就完成了长按的识别。