/*******************************************************************************
*按键模块
*文件: Key.c
*编写人: 崔杰城
*硬件支持:51单片机 实验环境为12M晶振的情况下,P3.0 P3.1 P3.2 P3.3各接一个按键
按键按下时,单片机引脚输入低电平,按键释放时,引脚输入高电平
*描述: 本模块使用一种基于状态转移的独立按键程序,能实现按键的去抖动以及识
别按键的短按和长按,首先按键程序进入按键初始状态(按键释放状态S1),
在此状态下,检测按键是否按下,如果有按下,进入按键消抖状态S2,计数
值加1,在下一次执行按键程序的时候,再次检测按键是否按下,如果没有按
下,计数值清0,返回初始状态S1,如果有按下则计数值再加1,当计数值达
到短按阀值时,代表按键真正按下而非抖动,返回按键值,并继续计数。当
计数值达到长按阀值时,表明长按事件发生。本程序通过监控按键按下的时
间(计数值),短按是释放执行,长按是到时间执行。
*备注: 如果要增加或者减少硬件连接的按键数目,程序需要作相应的调整
*********************************************************************************/
#include <reg52.h>
#include "MacroAndConst.h"
#include "Key.h"
#include "Led.h"
#define KEY_SHORT_PERIIOD 1 //短按计数阀值,可以通过改变该值调整短按的灵敏度
#define KEY_LONG_PERIOD 4000 //长按计数阀值,可以通过改变该值调整长按的灵敏度
sbit io_key_1=P3^0; //按键1连接在P3.0
sbit io_key_2=P3^1; //按键2连接在P3.1
sbit io_key_3=P3^2; //按键3连接在P3.2
sbit io_key_4=P3^3; //按键4连接在P3.3
/*******************************************************************************
*函数名:底层按键驱动程序
*调用: KeyScan();
*参数: 无
*返回值:KEY_VALUE:代表哪几个按键被按下
*结果: KeyScan()作为底层按键的驱动程序,为上层按键扫描提供一个接口
*********************************************************************************/
static uint8 KeyScan()
{
uint8 KEY_VALUE=0;
if(io_key_1==0)
KEY_VALUE=KEY_VALUE+KEY_VALUE_1;
if(io_key_2==0)
KEY_VALUE=KEY_VALUE+KEY_VALUE_2;
if(io_key_3==0)
KEY_VALUE=KEY_VALUE+KEY_VALUE_3;
if(io_key_4==0)
KEY_VALUE=KEY_VALUE+KEY_VALUE_4;
return(KEY_VALUE);
}
/*******************************************************************************
*函数名:键值筛选程序
*调用: Get_LastKeyValue();
*参数: 无
*返回值:KEY_VALUE_1或者KEY_VALUE_2或KEY_VALUE_3或KEY_VALUE_4
*结果: 筛选出按下的几个按键中优先级最高的按键值,其中优先级按键1>按键2>按键3>
按键4,比如如果同时按下按键2,按键4,返回代表按键2的键值KEY_VALUE_2
*********************************************************************************/
static uint8 Get_LastKeyValue(uint8 KeyTemp)
{
if((KeyTemp&KEY_VALUE_1)==KEY_VALUE_1) //如果按下的按键中有按键1,则返回按键1的值KEY_VALUE_1
return(KEY_VALUE_1);
if((KeyTemp&KEY_VALUE_2)==KEY_VALUE_2) //如果按下的按键中没有按键1有按键2,则返回按键2的值KEY_VALUE_2
return(KEY_VALUE_2);
if((KeyTemp&KEY_VALUE_3)==KEY_VALUE_3) //如果按下的按键中没有按键1和按键2,有按键3,则返回按键2的值KEY_VALUE_3
return(KEY_VALUE_3);
if((KeyTemp&KEY_VALUE_4)==KEY_VALUE_4) //如果按下的按键中没有按键1,2,3,有按键4,则返回按键2的值KEY_VALUE_4
return(KEY_VALUE_4);
return(KEY_NULL);
}
/*******************************************************************************
*函数名:上层按键扫描程序
*调用: GetKey();
*参数: pKeyValue:*pKeyValue代表哪个按键被按下,为短按还是长按。通过指针变量作
为函数参数,可以改变主函数中*pKeyValue对应的变量的值
*返回值:无
*结果: *pKeyValue为(KEY_VALUE_1|KEY_SHORT)执行按键1短按的操作
*pKeyValue为(KEY_VALUE_1|KEY_LONG)执行按键1长按的操作
*pKeyValue为(KEY_VALUE_2|KEY_SHORT)执行按键2短按的操作
*pKeyValue为(KEY_VALUE_2|KEY_LONG)执行按键2长按的操作
以此类推
*********************************************************************************/
static void GetKey(uint8 *pKeyValue)
{
static uint32 KeyCount=0; //按键计数值,当等于短按计数阀值和长按计数阀值时程序执行相应操作
static uint8 KeyState=KEY_STATE_RELEASE;
static LastKey=KEY_NULL;
static uint8 KeyTemp=KEY_NULL;
KeyTemp=KeyScan();
switch(KeyState)
{
case KEY_STATE_RELEASE:
{
if(KeyTemp!=KEY_NULL)
{
LastKey=Get_LastKeyValue(KeyTemp); //如果同时有几个按键按下,选择优先级最高的按键
KeyState=KEY_STATE_WOBBLE;
KeyCount++;
}
}
break;
case KEY_STATE_WOBBLE:
{
if(KeyTemp==KEY_NULL)
{
KeyState=KEY_STATE_RELEASE;
LastKey=KEY_NULL;
KeyCount=0;
}
else if((KeyTemp&LastKey)==LastKey) //如果上一个被检测到为低电平的按键仍然为低电平(此处屏蔽掉其他抖动的按键)
{
if(KeyCount==KEY_SHORT_PERIIOD)
{
KeyState=KEY_STATE_PRESS;
}
KeyCount++;
}
else
{
LastKey=Get_LastKeyValue(KeyTemp); //如果上一个被检测到为低电平的按键不为低电平并且计数值未到达短按阀值,这时候有其他按键抖动
KeyCount=1; //则其他抖动的按键中优先级最高的按键被视为抖动,进入去抖状态,计数值加1
}
}
break;
case KEY_STATE_PRESS:
{
if(KeyTemp==KEY_NULL)
{
KeyState=KEY_STATE_RELEASE;
KeyTemp=LastKey|KEY_SHORT; //短按是释放按键后执行
LastKey=KEY_NULL;
KeyCount=0;
}
else if((KeyTemp&LastKey)==LastKey)
{
KeyCount++;
if(KeyCount==KEY_LONG_PERIOD)
{
KeyState=KEY_STATE_LONG;
KeyTemp=LastKey|KEY_LONG; //长按是时间到(计数值达到阀值)执行
}
}
else
{
KeyState=KEY_STATE_WOBBLE;
KeyTemp=LastKey|KEY_SHORT;
LastKey=Get_LastKeyValue(KeyTemp);
KeyCount=1;
}
}
break;
case KEY_STATE_LONG:
{
if(KeyTemp==KEY_NULL)
{
KeyState=KEY_STATE_RELEASE;
KeyTemp=KEY_NULL;
LastKey=KEY_NULL;
KeyCount=0;
}
else if((KeyTemp&LastKey)==LastKey)
{
KeyCount++;
KeyTemp=LastKey|KEY_LONG;
}
else
{
KeyState=KEY_STATE_WOBBLE;
LastKey=Get_LastKeyValue(KeyTemp);
KeyCount=1;
}
}
break;
default:break;
}
*pKeyValue=KeyTemp;
}
void Key_Process()
{
uint8 KeyValue=KEY_NULL;
GetKey(&KeyValue);
if(KeyValue==(KEY_VALUE_1|KEY_SHORT))
{
L1=~L1;
}
if(KeyValue==(KEY_VALUE_1|KEY_LONG))
{
L2=0;
}
if(KeyValue!=(KEY_VALUE_1|KEY_LONG))
{
L2=1;
}
if(KeyValue==(KEY_VALUE_2|KEY_SHORT))
{
L3=~L3;
}
if(KeyValue==(KEY_VALUE_2|KEY_LONG))
{
L4=0;
}
if(KeyValue!=(KEY_VALUE_2|KEY_LONG))
{
L4=1;
}
if(KeyValue==(KEY_VALUE_3|KEY_SHORT))
{
L5=~L5;
}
if(KeyValue==(KEY_VALUE_3|KEY_LONG))
{
L6=0;
}
if(KeyValue!=(KEY_VALUE_3|KEY_LONG))
{
L6=1;
}
if(KeyValue==(KEY_VALUE_4|KEY_SHORT))
{
L7=~L7;
}
if(KeyValue==(KEY_VALUE_4|KEY_LONG))
{
L8=0;
}
if(KeyValue!=(KEY_VALUE_4|KEY_LONG))
{
L8=1;
}
}