1-头文件:KeyBoard.h
#ifndef _Key_Board_h_
#define _Key_Board_h_
#define Key_Up 0x3E //上箭头
#define Key_Down 0x3D //下箭头
#define Key_Add 0x3B //加
#define Key_Sub 0x37 //减
#define Key_Enter 0x2F //回车
#define Key_Return 0x1F //返回
#define Key_LR 0x33 //左右组合键
//可以在此定义其它组合键……
#define Key_NULL 0xFF //无任何按键
//声明几个需要在外部调用的函数
extern void Key_Board_Init(void);//键盘接口初始化
extern u8 Read_Key(void); //读键函数,返回键盘缓冲区中的键值
extern void Key_In(void);//处理按键输入函数,在定时器中断里调用
extern void Key_Board_Test(void); //键盘接口测试函数(仅在调试阶段使用)
#endif
2-源文件:KeyBoard.c
//#include "includes.h" //公共头文件
#include "Key_Board.h"
//键盘缓冲区相关常量定义
#define KeyBuffLen 8 //定义键值环形缓冲区长度为8(缓冲区大小可自由定义,只要大于0即可)
//定义一个键盘缓冲区结构体
struct Struct_KeyBoardBuff
{
u8 buff[KeyBuffLen];//键值环形缓冲区
u8 in; //写键值指示(定时器中断写)
u8 out; //读键值指示(用户读)
}Key;
/*************************************************************************
函数原型:void Key_Board_Init(void)
函数功能:对键盘接口进行初始化,即把键值缓冲区清零
传入参数:无
返回参数:无
全局变量:直接操作键盘缓冲区结构体
设 计:莫汉伟 amo73@126.com
修改日期:2007-9-5
备 注:仅在上电初始化的时候被调用一次
**************************************************************************/
void Key_Board_Init(void)
{
memset(&Key,0,sizeof(Key));
}
/*************************************************************************
函数原型:u8 Read_Key(void)
函数功能:从键值缓冲区读取一个键值
传入参数:无
返回参数:u8型按键值,如果缓冲区为空,则返回-1
设 计:莫汉伟 amo73@126.com
修改日期:2007-9-5
备 注:供用户程序调用;用户不用关心键盘底层硬件。
**************************************************************************/
u8 Read_Key(void)
{
u8 Value;
if(Key.out != Key.in)
{
Value=Key.buff[Key.out++];//"读"还没有追上"写",缓冲区有键值,读之
if(Key.out >= KeyBuffLen) //如果"读"跑到了队列尾部,则重新跳回原点
{
Key.out=0;
}
}
else
{
Value=Key_NULL;//"读"追上了"写",缓冲区没有键值,返回空键值
}
return(Value);
}
//判断一个键值的键数(在本硬件里1bit对应一个按键,0表示按键按下)
u8 JudgeKey(u8 key)
{
u8 i,count=0;
for(i=0;i<6;i++)
{
if((key & 0x01)==0)
count++;
key >>= 1;
}
return(count);
}
/*************************************************************************
函数原型:void Key_In(void)
函数功能:在定时器中断里每10ms调用1次,处理按键输入,并将按键值放入键值缓冲区中。
支持单键、双键组合键
传入参数:无
返回参数:无
设 计:莫汉伟 amo73@126.com
修改日期:2007-10-12
备 注:详细功能和处理算法请参照本文件相关的流程图和文档
**************************************************************************/
enum KeyFSM_Enum //按键状态有限状态机
{
_Key_Idle=0, //空闲
_Key1_down, //单键按下消抖
_Key1_press, //单键按下
_Key1_up, //单键抬起消抖
_Key2_down, //双键按下消抖
_Key2_press, //双键按下
_Key2_up, //双键抬起消抖
_Key_confirm, //按键确认成功
};
//处理扫描按键、判断按键、保存键值等。在定时器中断里(周期为10ms以上即可)调用本函数。
void Key_In(void)
{
static u8 Key_Input=0;
//在此添加获取键值代码(参照硬件电路图)
static u8 volatile step=0;//步骤
u8 NewKey = uPSD.DATAIN_A & 0x3F;//读取按键
//获取键值代码结束
u8 num=JudgeKey(NewKey);//判断当前有几个按键按下
switch(step)//状态机
{
case _Key_Idle://空闲
{
switch(num)
{
case 1://单键
{
Key_Input = NewKey;//保存键值
step = _Key1_down;//单键按下消抖
SoundLight_ms(_TypeLcdBkLED,9000);//LCD背光亮一段时间
break;
}
case 2://双键
{
Key_Input = NewKey;//保存键值
step = _Key2_down;//双键按下消抖
SoundLight_ms(_TypeLcdBkLED,9000);//LCD背光亮一段时间
break;
}
default://其它
{
break;
}
}
break;
}
case _Key1_down://单键按下消抖
{
switch(num)
{
case 1://单键
{
if(NewKey == Key_Input)//键值不变
step = _Key1_press;//单键按下
else
step = _Key_Idle;//空闲
break;
}
case 2://双键
{
Key_Input = NewKey;//保存键值
step = _Key2_down;//双键按下消抖
break;
}
default://其它
{
step = _Key_Idle;//空闲
break;
}
}
break;
}
case _Key1_press://单键按下
{
switch(num)
{
case 1://单键
{
if(NewKey != Key_Input)//键值改变
step = _Key1_up;//单键抬起消抖
break;
}
case 2://双键
{
Key_Input = NewKey;//保存键值
step = _Key2_down;//双键按下消抖
break;
}
default://其它
{
step = _Key1_up;//单键抬起消抖
break;
}
}
break;
}
case _Key1_up://单键抬起消抖
{
switch(num)
{
case 1://单键
{
if(NewKey == Key_Input)//键值不变
step = _Key1_press;//单键按下
else
step = _Key_confirm;//按键确认成功
break;
}
case 2://双键
{
Key_Input = NewKey;//保存键值
step = _Key2_down;//双键按下消抖
break;
}
default://其它
{
step = _Key_confirm;//按键确认成功
break;
}
}
break;
}
case _Key2_down://双键按下消抖
{
if(NewKey == Key_Input)//键值不变
step = _Key2_press;//双键按下
else
step = _Key_Idle;//空闲
break;
}
case _Key2_press://双键按下
{
if(num==0)//无键
step = _Key2_up;//双键抬起消抖
break;
}
case _Key2_up://双键抬起消抖
{
if(num==0)//无键
step = _Key_confirm;//按键确认成功
break;
}
default://出现异常,流程复位
{
step = _Key_Idle;//空闲
break;
}
}
if(step == _Key_confirm)//按键确认成功
{
step = _Key_Idle;//空闲
// SoundLight_ms(_TypeLcdBkLED,9000);//LCD背光亮一段时间
//放入键值缓冲区中
if(Key_Input != 0)//如果键值有效,则放入缓冲区中
{
// SoundLight_ms(_TypeBeep,30);//蜂鸣器发声30ms
// menu_auto_return_s = 60;//60秒后菜单自动返回
Key.buff[Key.in++] = Key_Input;
if(Key.in >= KeyBuffLen)//如果"写"跑到了队列尾部,则重新跳回原点
{
Key.in=0;
}
}
}
//"写"只管在前面跑,不用管"读"在后面怎么追;如果"写"跑了一圈又超过了"读"
//就算是自动将缓冲区清空了,这样的算法具有天生的容错性,只会丢掉前面的键值,
//而不会崩溃。
} |