蓝桥杯嵌入式CT117E硬件开发平台 | 按键状态机实现方法
蓝桥杯历年赛题有一届考到了按键多个状态,比如长按短按,长按快速累加等。因此本驱动则是针对这种任务要求而设计。具体思路和实现方法如下:
- 思路:利用定时器间隔扫描按键驱动函数,定时器间隔时间则可以作为消抖时间,从而实现消抖过程而不用延时函数消抖。比如定时器设计5MS中断一次:2次中断则检测一次按键值,若按键值不为0xff(根据经验06章节讲的按键延时消抖方法设计的按键编码来更改的,按键没有按下则值为0xff,按下的话返回对应的按键编码值:0 - 4)则存取按键值为第一次按键扫描值,进入第二层状态,否则还是继续间隔扫描,检测按键值不为0xff时再存入按键值;在第二层状态中:再过两次中断(10MS)再次扫描按键,如果此次按键值等于第一次按键扫描值,则确定了有按键按下,进入第三层状态;在第三层状态中:再过两次中断判断按键有无松开,若是没有,则累加计时,若计时超过长按时间(自己设置的多久算长按),则做一个变量累加计时,这个计时则是判断长按多久要设置加的值快速加一,若按键松开,则判断计时时间是否小于按键长按时间,若小于长按时间则算是短按。 --总结:其实按键状态机无非就是依靠多个标志变量判断当前按键所处状态,对于有时许处理要求的任务来说,状态设计一定是重点。
- 实现方法:首先是.h中设计的宏定义和按键状态机结构体。具体如下:
#define RB1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define RB2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
#define RB3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define RB4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)
typedef struct{
u8 KEY_VALUE;
JUDGE_ENUM IS_Key_ShortPress;
JUDGE_ENUM IS_Key_LongPress;
JUDGE_ENUM IS_Key_LongFresh;
JUDGE_ENUM IS_Key_Touch;
}KEYSCANF_TypeDef;
extern KEYSCANF_TypeDef KEYSCANF_Structure;
#define KEY_LONGSTATUS_Time 800000/GENERAL_TIM_SetUs
#define KEY_EliShaking_Time 10000/GENERAL_TIM_SetUs
#define Key_LongTimeSet 100000/GENERAL_TIM_SetUs
- 其次则是.c文件中的函数设计,思路已经写过,直接上代码:
uint8_t Key_Scan(void)
{
uint8_t key_value = 0xff;
if(RB1 == 0){
key_value = 1;
}
if(RB2 == 0){
key_value = 2;
}
if(RB3 == 0){
key_value = 3;
}
if(RB4 == 0){
key_value = 4;
}
return key_value;
}
u8 keyCheck = 0;
uint8_t keyState = 0;
uint16_t keyPrev = 0xff;
u32 keyLongCheck = 0;
u16 Key_LongTime = 0;
u8 keyCountTime = 0;
KEYSCANF_TypeDef KEYSCANF_Structure = {0xff,FAUSE,FAUSE,FAUSE,FAUSE};
void Key_Interrup(void)
{
uint8_t keyPress = 0xff;
keyCountTime ++;
if(keyCountTime >= KEY_EliShaking_Time)
{
keyCountTime = 0;
keyCheck = 1;
}
if(keyCheck == 1)
{
keyCheck = 0;
keyPress = Key_Scan();
switch(keyState)
{
case 0://按键未按下态
if(keyPress != 0xff)
{
keyPrev = keyPress;
keyState = 1;
}
else
{
keyState = 0;
}
break;
case 1://表示有按键按下,判断当前值和上一次的值是否一样,若不一样则为抖动!
if(keyPress == keyPrev)
{
keyState = 2;
}else{
keyState = 0;
keyPrev = 0xff;
}
break;
case 2:
if(keyPress != keyPrev)
{
if(keyLongCheck < KEY_LONGSTATUS_Time)
{
KEYSCANF_Structure.IS_Key_ShortPress = TRUE;
KEYSCANF_Structure.KEY_VALUE = keyPrev;
}
KEYSCANF_Structure.IS_Key_LongPress = FAUSE;
keyPrev = 0xff;
keyState = 0;
keyLongCheck = 0;
Key_LongTime = 0;
}else{
keyLongCheck++;
if(keyLongCheck >= KEY_LONGSTATUS_Time)
{
if(KEY_LONGSTATUS_Time > 65535)
keyLongCheck = KEY_LONGSTATUS_Time;
KEYSCANF_Structure.KEY_VALUE = keyPrev;
KEYSCANF_Structure.IS_Key_ShortPress = FAUSE;
KEYSCANF_Structure.IS_Key_LongPress = TRUE;
}
}
break;
default : break;
}
}
if(KEYSCANF_Structure.IS_Key_LongPress == TRUE)
{
Key_LongTime ++;
if(Key_LongTime >= Key_LongTimeSet)
{
Key_LongTime = 0;
KEYSCANF_Structure.IS_Key_LongFresh = TRUE;
}
}
}