额,忘了,还没有“炫耀”俺的代码呢??:lol
俺这菜鸟,好不容易才写出来这个程序,炫耀一下不过分吧;P——高手请砖下留情:handshake
/******************************************************************************************************************************************
* 文件名称: keypad.c
* 功能说明: 基于状态机的矩阵键盘的实现代码
* 作者邮箱: XIANSir@yeah.net
* 注意事项:
* 版本日期: 2011年3月31日
* 升级记录: 2010年3月31日 将KEY_RD()的定义由(P2 >> 4)&0x0F 改为 ((P2 >> 4)&0x0F)
* 此修改去除了一个严重的BUG,此BUG与C语言的运算符优先级有关
*******************************************************************************************************************************************/
#include "sysconf.h"
#include "typedef.h"
#include "8052Hal.h"
#include "keypad.h"
/*矩阵键盘的输入脚接P2的低四位,输出脚接P2的高四位
* 注意:矩阵键盘的输入是MCU的输出,矩阵键盘的输出是MCU的输入*/
#define KEY_LO() P2 &= 0xF0 //矩阵键盘所有输入脚都置低
#define KEY_HI() P2 |= 0x0F //矩阵键盘所有输入脚都置高
#define KEY_L(i) P2 &= ~(1<<i) //矩阵键盘指定输入脚 置低
#define KEY_RD() ((P2 >> 4)&0x0F)//读取矩阵键盘输出脚的状态
bit NeedScan = 0; //键盘每10ms扫描一次,扫描间隔由T0产生
s_Key S_Key = {NO_KEY,K_STAT_0}; //包含键盘所有有用信息的结构体:按键值,键盘状态
/******************************************************************************************************************************************
* 函数名称: PadInit()
* 功能说明: 矩阵键盘初始化例程,配置矩阵键盘引脚并初始化间隔时钟T0
* 输 入: 无
* 输 出: 无
* 注意事项: 1、本矩阵键盘连接在51的P2端口上
* 2、本矩阵键盘使用了51的定时器资源T0
******************************************************************************************************************************************/
void PadInit(void)
{
P2 = 0xFF; //51引脚作为输入时必须先置高
TMOD = 0x01; //配置T0为16 bit定位时器模式
TH0 = T10ms_LO; //设置定时器溢出中断周期为10ms
TL0 = T10ms_HI;
EA = 1; //全局中断开
ET0 = 1; //允许T0中断
PT0 = 0; //T0优先级设为低
TR0 = 1; //启动T0开始计时
}
/******************************************************************************************************************************************
* 函数名称: OnceKey()
* 功能说明: 进行一次键盘状态的扫描获取
* 输 入: 无
* 输 出: byte 扫描到的按键值
* 注意事项: 1、编码0xFF(NO_KEY)表示没有按键被按下
* 2、本函数扫描按键没有进行消抖,下面的ScanKey()函数在本函数的基础上进行了基于状态机机制的机械消抖操作
******************************************************************************************************************************************/
byte OnceKey(void)
{
ui08 i = 0;
byte key = NO_KEY;
KEY_LO();
if(KEY_RD() == 0x0F)
{
KEY_HI();
return NO_KEY; //没有按键按下,直接返回
}
for(i = 0;i < 4;i++)
{
KEY_HI();
KEY_L(i);
key = KEY_RD();
switch(key)
{
case ((~1) & 0x0F):
key = 4*i + 0;
break;
case ((~2) & 0x0F):
key = 4*i + 1;
break;
case ((~4) & 0x0F):
key = 4*i + 2;
break;
case ((~8) & 0x0F):
key = 4*i + 3;
break;
default:
key = 0xFF;
}
if(key < 0x10)
{
return key;
}
}
return NO_KEY;
}
/******************************************************************************************************************************************
* 函数名称: ScanKey()
* 功能说明: 矩阵键盘扫描,返回得到的代表被按键位置的码值
* 输 入: 无
* 输 出: byte 扫描到的按键值
* 注意事项: 编码0xFF(NO_KEY)表示没有按键被按下
******************************************************************************************************************************************/
byte ScanKey(void)
{
byte key =NO_KEY;
byte ret =NO_KEY;
if(NeedScan == 0)
{
return NO_KEY;
}
NeedScan = 0; //防止重复进入
key = OnceKey();
switch(S_Key.state)
{
case K_STAT_0:
if(key != NO_KEY)
{
S_Key.v_key = key;
S_Key.state = K_STAT_1;
}
break;
case K_STAT_1:
if(key == S_Key.v_key)
{
S_Key.state = K_STAT_2;
}
else
{
S_Key.v_key = NO_KEY;
S_Key.state = K_STAT_0;
}
break;
case K_STAT_2:
if(key == S_Key.v_key)
{
ret = S_Key.v_key;
S_Key.state = K_STAT_3;
}
else
{
S_Key.v_key = NO_KEY;
S_Key.state = K_STAT_0;
}
break;
case K_STAT_3:
if(key == NO_KEY)
{
S_Key.v_key = NO_KEY;
S_Key.state = K_STAT_0;
}
break;
default:
ret = NO_KEY;
}
return ret;
}
/******************************************************************************************************************************************
* 函数名称: ParseKey()
* 功能说明: 将按键的编码值映射到更易理解的“按键上标识的字符”
* 输 入: byte key 按键的编码值
* 输 出: char 按键上标识的字符
* 注意事项: 这个映射需要根据自己矩阵键盘上的实际标注来修改,但是这显然很容易
******************************************************************************************************************************************/
char ParseKey(byte key)
{
char ch = '\0';
switch(key)
{
case 0x00:
ch = '1';
break;
case 0x01:
ch = '2';
break;
case 0x02:
ch = '3';
break;
case 0x03:
ch = 'A';
break;
case 0x04:
ch = '4';
break;
case 0x05:
ch = '5';
break;
case 0x06:
ch = '6';
break;
case 0x07:
ch = 'B';
break;
case 0x08:
ch = '7';
break;
case 0x09:
ch = '8';
break;
case 0x0A:
ch = '9';
break;
case 0x0B:
ch = 'C';
break;
case 0x0C:
ch = '*';
break;
case 0x0D:
ch = '0';
break;
case 0x0E:
ch = '#';
break;
case 0x0F:
ch = 'D';
break;
default:
ch = '\0';
}
return ch;
}
/******************************************************************************************************************************************
* 函数名称: T0Isr
* 功能说明: 产生10ms定时器0中断,在中断中置位NeedScan来驱动矩阵键盘扫描
* 输 入: 无
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void T0Isr(void) interrupt 1
{
TR0 = 0;
TH0 = T10ms_LO;
TL0 = T10ms_HI+10; //9:这4条C语句执行消耗的时间
TR0 = 1;
NeedScan = 1;
}
|