将无自锁功能的按键通过对其单击,双击,长按等状态,进行分配相应的功能,扩展按键功能,调用相关函数即可。
1.轮询方式
key.c
#include "firmware.h"
#include "key.h"
u8 Key1_Lock_Flag = 0;
u16 Key1_Cnt = 0;//u8 0-255;u16 0-65535
u8 KeyNum = 0;
u8 Key_Short_Flag = 0;
u8 Key1_Cnt2 = 0;
u8 Key1_Times = 0;
u8 Key1_Cnt3 = 0;
u8 Key_Couple_Flag = 0;
u8 Key12_Lock_Flag = 0;
u16 Key12_Cnt = 0;
u8 Key2_Lock_Flag = 0;
u16 Key2_Cnt = 0;
按键单击消抖
void Key_Scan1(void)
{
if(KEY1 == 1)//按键没有按下
{
Key1_Lock_Flag = 0;//清零自锁标志
Key1_Cnt = 0;//清零计数标志
}
else if(Key1_Lock_Flag == 0)
{
Key1_Cnt ++;//累计按键消抖延时次数
if(Key1_Cnt > Key_Delay_Time)
{
Key1_Cnt = 0;//清零计数变量
Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
}
}
}
按键短按与长按
void Key_Scan2(void)
{
if(KEY1 == 1)//按键没有按下
{
Key1_Lock_Flag = 0;//清零自锁标志
Key1_Cnt = 0;//清零计数标志
if(Key_Short_Flag == 1)
{
Key_Short_Flag = 0;
KeyNum = 1;//赋短按键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
}
}
else if(Key1_Lock_Flag == 0)
{
Key1_Cnt ++;//累计按键消抖延时次数
if(Key1_Cnt > Key_Delay_Time)
{
Key_Short_Flag = 1;//大于消抖时间,有可能是长按也有可能是短按
}
if(Key1_Cnt > Key_Long_Time)
{
Key_Short_Flag = 0;//进入长按,取消短按标志位
Key1_Cnt = 0;
KeyNum = 2;//赋长按键值编码。
Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
}
}
}
按键短按与连按
void Key_Scan3(void)
{
if(KEY1 == 1)//按键没有按下
{
Key1_Lock_Flag = 0;//清零自锁标志
Key1_Cnt = 0;//清零计数标志
}
else if(Key1_Lock_Flag == 0)
{
Key1_Cnt ++;//累计按键消抖延时次数
if(Key1_Cnt > Key_Delay_Time)
{
Key1_Cnt = 0;//清零计数变量
Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
}
}
else if(Key1_Cnt < Key_Long_Time)//按键持续按下自锁标志为1,不可进入上述步骤
{
Key1_Cnt ++;//连按超过一定时限,进入连按
}
else
{
Key1_Cnt2 ++;//连击时间间隔计数
if(Key1_Cnt2 > Key_Long_Time2)//每超过连击时间间隔
{
Key1_Cnt2 = 0;//连击时间间隔计数器清零
KeyNum = 1;//与单击相同实现连续单击效果
}
}
}
按键单击、双击与连击
void Key_Scan4(void)
{
if(KEY1 == 1)//按键没有按下
{
Key1_Lock_Flag = 0;//清零自锁标志
Key1_Cnt = 0;//清零计数标志
if(Key1_Times > 0)
{
Key1_Cnt3 ++;//当前距离前一次按下间隔时间
if(Key1_Cnt3 > Key_Double_Time)//超过双击有效间隔时间
{
Key1_Cnt3 = 0;
Key1_Times = 0;
}
}
}
else if(Key1_Lock_Flag == 0)
{
Key1_Cnt ++;//累计按键消抖延时次数
if(Key1_Cnt > Key_Delay_Time)
{
Key1_Cnt = 0;//清零计数变量
Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
Key1_Times ++;//统计按键按下次数
Key1_Cnt3 = 0;
if(Key1_Times == 1)
{
KeyNum = 1;//按键单击
}
else if(Key1_Times == 2)
{
KeyNum = 2;//按键双击
}
else if(Key1_Times == 3)
{
KeyNum = 3;//按键三击
}
}
}
else if(Key1_Cnt < Key_Long_Time)//按键持续按下自锁标志为1,不可进入上述步骤
{
Key1_Cnt ++;//连按超过一定时限,进入连按
}
else
{
Key1_Cnt2 ++;//连击时间间隔计数
if(Key1_Cnt2 > Key_Long_Time2)//每超过连击时间间隔
{
Key1_Cnt2 = 0;//连击时间间隔计数器清零
KeyNum = 1;//与单击相同实现连续单击效果
}
}
}
组合按键(不区分先后顺序)
void Key_Scan5(void)
{
if((KEY1 || KEY2) == 1)//按键没有按下
{
Key_Couple_Flag = 0;
Key12_Lock_Flag = 0;//清零自锁标志
Key12_Cnt = 0;//清零计数标志
}
else if(Key12_Lock_Flag == 0)
{
Key12_Cnt ++;//累计按键消抖延时次数
Key_Couple_Flag = 1;//组合按键按下
if(Key12_Cnt > Key_Delay_Time)
{
Key12_Cnt = 0;//清零计数变量
Key12_Lock_Flag = 1;//自锁标志,防止按键多次触发
KeyNum = 12;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
}
}
if(KEY1 == 1)//按键没有按下
{
Key1_Lock_Flag = 0;//清零自锁标志
Key1_Cnt = 0;//清零计数标志
}
else if((Key1_Lock_Flag == 0) && (Key_Couple_Flag == 0))
{
Key1_Cnt ++;//累计按键消抖延时次数
if(Key1_Cnt > Key_Delay_Time)
{
Key1_Cnt = 0;//清零计数变量
Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
}
}
if(KEY2 == 1)//按键没有按下
{
Key2_Lock_Flag = 0;//清零自锁标志
Key2_Cnt = 0;//清零计数标志
}
else if((Key2_Lock_Flag == 0) && (Key_Couple_Flag == 0))
{
Key2_Cnt ++;//累计按键消抖延时次数
if(Key2_Cnt > Key_Delay_Time)
{
Key2_Cnt = 0;//清零计数变量
Key2_Lock_Flag = 1;//自锁标志,防止按键多次触发
KeyNum = 2;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
}
}
}
组合按键(区分先后顺序)
void Key_Scan6(void)
{
if(KEY1 == 1)//按键没有按下
{
Key1_Lock_Flag = 0;//清零自锁标志
Key1_Cnt = 0;//清零计数标志
}
else if(Key1_Lock_Flag == 0)
{
Key1_Cnt ++;//累计按键消抖延时次数
if(Key1_Cnt > Key_Delay_Time)
{
Key1_Cnt = 0;//清零计数变量
if(KEY2 == 0)
{
Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
KeyNum = 3;//赋键值编码。
}
else
{
Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
KeyNum = 1;//赋键值编码。
}
}
}
if(KEY2 == 1)//按键没有按下
{
Key2_Lock_Flag = 0;//清零自锁标志
Key2_Cnt = 0;//清零计数标志
}
else if(Key2_Lock_Flag == 0)
{
Key2_Cnt ++;//累计按键消抖延时次数
if(Key2_Cnt > Key_Delay_Time)
{
Key2_Cnt = 0;//清零计数变量
Key2_Lock_Flag = 1;//自锁标志,防止按键多次触发
KeyNum = 2;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
}
}
}
key.h
#ifndef __KEY_H
#define __KEY_H
#include "firmware.h" //IO define
#define Key_Delay_Time 100 //按实际调整
#define Key_Long_Time 500 //长按持续时间
#define Key_Long_Time2 500 //长按每次变化间隔时间
#define Key_Double_Time 200 //双击有效间隔时间
void Key_Scan1(void)
void Key_Scan2(void)
void Key_Scan3(void)
void Key_Scan4(void);
void Key_Scan5(void);
void Key_Scan6(void);
#define KEY1 IN1 //单片机IO
#define KEY2 IN2 //单片机IO
#endif
2.定时器检测
开启定时器中断,将计时时间设置为50ms,即50ms扫描一次按键,实现检测按键是否按下和连按。
struct Key
{
char KeyStaute;//是否按下
char Continuous;//是否连按
int KeyNumberContinuous;//连按统计
};
struct Key key1,key2,key3,key4;//定义结构体变量,代表四个按键
void Key_Scan(struct Key * key,GPIO_TypeDef* GPIO_Port,uint16_t GPIO_Pin)
{
if(!HAL_GPIO_ReadPin(GPIO_Port,GPIO_Pin))//按键按下被拉低
{
if(key->KeyStaute)
{
key->KeyContinueNumber++;
if(key->KeyContinueNumber>20)//长按超过1s
{
key->Continuous = 1;
}
}
else
{
key->KeyStaute = 1;
}
}
else
{
key->KeyStaute = 0;
key->KeyContinueNumber = 0;
key->Continuous = 0;
}
}
按键自锁
u16 z_count = 0;
u8 z_en = 0;
u8 z_flag = 0;
void z_key(void)
{
if(IN3 == 0)
{
z_count ++;
if(z_count >= 300)//调试更改
{
z_count = 300;
}
}
if((IN3 == 1) && (z_count >= 300))
{
z_en^=1;//异或,相同为0,不同为1
z_count = 0;
}
if(z_en == 1)
{
OUT11 = 1;//按单次
z_flag = 1;
}
else if(z_en == 0)
{
OUT11 = 0;//按双次
z_flag = 0;
}
}