一开始用的正点原子的按键扫描,代码简单,但用于多功能按键的实现就有点不够用了,后来我自己写了一下,新手刚写完,望多多指教。谢谢。
-
按键对应IO口.h(写在对应H文件里)
#define KEY_mid GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)
#define KEY_up GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_11)
#define KEY_down GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)
#define KEY_left GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
#define KEY_right GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_4)
-
按键扫描结构体.h
typedef struct
{
uchar PressTime;
uchar LooseTime;
uchar press;//按下
uchar loose;//一直松开
uchar PressLoose;//按下松开有效
uchar ContiPress;
} key_stat;
typedef struct
{
uchar MPressTime;
uchar MLooseTime;
uchar MShortPress;//短按下
uchar MLongPress;//长按下
uchar Loose;//一直松开
uchar MPressLoose;//按下松开有效
uchar MPressNumber;
uchar MContiPress;//连按与否
} key_multi;
extern key_stat Key_Up;
extern key_stat Key_Down;
extern key_multi MKey_Right;
extern key_multi MKey_Left;
extern key_multi MKey_Right;
extern key_multi MKey_Left;
void Key_Scan(uint8_t mode);
void Key_Multi(void);
-
运用结构体.c
key_stat Key_Up;
key_stat Key_Down;
key_stat Key_Left;
key_stat Key_Right;
key_stat Key_Mid;
key_multi MKey_Right;
key_multi MKey_Left;
//配置按键GPIO
-
按键扫描函数.c
void Key_Scan(uint8_t mode)//单个按键扫描
{
uint8_t Key_dely = 5;//我这个延时是在状态机里,每过1ms扫描.
//延时消抖根据自己的情况设定,延时函数或者定时器
//上按键
if (mode)//连按与按下一次有效
{
Key_Up.ContiPress = 0;//mode=0,按下为1,松开为0,按键按下只执行一次。
} //也就是松开才执行再次进入,当mode=1,则按下一直有效。
//比如通讯这块,需要当按键按下只发一次通讯,不连续发送
if (KEY_up == 0)//按键按下
{
if (!Key_Up.ContiPress)//连按与按下一次有效
{
Key_Up.LooseTime = 0;
Key_Up.PressTime++;
if (Key_Up.PressTime > Key_dely)//消抖
{
Key_Up.press = 1;
Key_Up.loose=2;//松开
Key_Up.ContiPress=1;
Key_Up.PressLoose=0;//按下松开
Key_Up.PressTime = 0;
}
}
}
else
{
Key_Up.LooseTime++;
if (Key_Up.LooseTime > Key_dely)
{
Key_Up.press = 0;
Key_Up.ContiPress = 0;
Key_Up.LooseTime=0;
Key_Up.PressTime = 0;
if(Key_Up.loose==2)//需要按下松开才进入,没有要求的可以删除
{ //有些时候需要按松开一次有效,比如松开发一次通讯
Key_Up.PressLoose=1;
Key_Up.loose=0;
}
else//松开一直有效
{
Key_Up.loose=1;
}
}
}
//下按键
if (mode)
{
Key_Down.ContiPress = 0;
}
if (KEY_down == 0)
{
if (!Key_Down.ContiPress)
{
Key_Down.PressTime++;
Key_Down.LooseTime = 0;
if (Key_Down.PressTime > Key_dely)
{
Key_Down.press = 1;
Key_Down.loose=2;
Key_Down.ContiPress=1;
Key_Down.PressTime = 0;
}
}
}
else
{
Key_Down.LooseTime++;
if (Key_Down.LooseTime > Key_dely)
{
Key_Down.press = 0;
Key_Down.loose=1;
Key_Down.ContiPress = 0;
Key_Down.LooseTime = 0;
Key_Down.PressTime = 0;
}
}
}
-
长短按键,组合按键,连击按键.c
void Key_Multi(void)
{
//长短按
if(KEY_right==0)
{
MKey_Right.MLooseTime=0;
MKey_Right.MPressTime++;
if(MKey_Right.MPressTime>200)
{
MKey_Right.MLongPress=1;
MKey_Right.Loose=0;
MKey_Right.MPressTime=0;
}
}
else
{
MKey_Right.MLooseTime++;
if(MKey_Right.MLooseTime>5)
{
if((MKey_Right.MPressTime>5)&&(!MKey_Right.MLongPress))
{
MKey_Right.MShortPress=1;
}
else
{
MKey_Right.MShortPress=0;
MKey_Right.Loose=0;
}
MKey_Right.MLongPress=0;
MKey_Right.MLooseTime=0;
MKey_Right.MPressTime=0;
}
}
//组合按键
/*直接用按键扫描组合*/
//按键次数,连按两次,三次(MPressNumber)等
if(KEY_left==0)
{
if(!MKey_Left.MContiPress)
{
MKey_Left.MLooseTime=0;
MKey_Left.MPressTime++;
if(MKey_Left.MPressTime>5)
{
MKey_Left.MPressNumber++;
MKey_Left.MContiPress=1;
MKey_Left.MPressTime=0;
}
}
}
else
{
MKey_Left.MLooseTime++;
if(MKey_Left.MLooseTime>5)
{
MKey_Left.MPressTime=0;
MKey_Left.MContiPress=0;
if(MKey_Left.MLooseTime>100)
{
MKey_Left.MLooseTime=0;
MKey_Left.MPressNumber=0;
}
}
}
}
-
应用
//主函数里调用
Key_Scan(0);
if (Key_Up.press)//上按键按下
{
//执行事件1
}
else//上按键松开
{
//执行事件2
}
//多功能按键
//长按
Key_Multi();
if(MKey_Right.MLongPress)//长按
{
//执行事件3
}
else if(MKey_Right.MShortPress)//短按
{
//执行事件4
}
else //松开
{
//执行事件5
}
//组合
Key_Scan(0);
if (Key_Up.press&&Key_Down.press)
{
//执行事件6
}
//连击
if (MKey_Left.MPressNumber==3)//连击三下有效
{
//执行事件7
}
注意
消抖我依赖于状态机里执行的,每隔1ms扫描一次,如果没有用状态机,一般用延时函数,定时器等来实现消抖,长短,连击按键的时间。