//适用于CEPARK 51开发板
/*****************************************************************************************************************
www.cepark.com 电子园 按键高阶攻略设计大赛
名称: 2*4矩阵键盘扫描 (状态机)
功能: 按键0单击时,点亮P0口的第1357个LED,按键1双击时,点亮P0口的2468个LED,按键2三击时,点亮P0口的所有的LED
按键按下的时间间隔小于200ms。 其他键按下时,LED状态不变
作者: alger2009
时间: 2009.12.30 星期三
版本: V1.0
其他: 该开发板的LED不是单个的LED组成,而是LED逻辑卡; 看门狗程序防止程序跑飞
*****************************************************************************************************************/
#include "reg52.h"
#include "intrins.h"
#include "key2.h"
/******宏定义***************************************************************************************************/
#define No_key 255 //无键按下返回值
/****** 定义全局变量********************************************************************************************/
unsigned char keyread_flag = 0; //矩阵键盘扫描标志位
unsigned char num = 0; //定时计数器计数变量
unsigned char outdata = 0; //返回值
/******2*4矩阵键盘扫描程序**********************************************************************************************
返回值:key_return
key_return = 0 单击
key_return = 1 双击
key_return = 2 三击
key_return = 其他,按键无效
************************************************************************************************************************/
unsigned char read_keyboard(void)
{
static unsigned char key_state = 0, key_value, key_line; // 列读取变量,行扫描码
static unsigned char key_times = 0; //按键击打次数
static unsigned char Tcount = 0; //按键连击计时变量
unsigned char key_return = No_key, i; //按键返回值
switch (key_state)
{
case 0: //key you meiyou cunzai jiancha //状态0功能: 按键扫描 连击计时 和连击超时处理
key_line = 0x10;
if (key_times != 0) Tcount++; //如果不是第一次击打,计时变量加1
if (Tcount > 20) //若连击按键按下时间间隔大于200毫秒
{
key_times = 0; // 按键击打次数归0
Tcount = 0; // 计时变量归0
}
for (i = 0; i
{
P2 = ~key_line; // 输入行扫描码
P2 = ~key_line; // 重复送一次
key_value = 0x0f & P2; // 读列电平
if (key_value == 0x0f)
key_line <<= 1; // 没有按键,继续扫描
else
{
key_state++; // 有按键,停止扫描
break; // 跳出按键扫描
}
}
break;
case 1: //状态1功能:确认按键 读取按键值
if (key_value == (0x0f & P2)) // 再次读列电平,若非抖动
{
switch (key_line | key_value) //行扫描码和列电平,确认按键
{ // 键盘编码,返回编码值
case 0x1e: //单击按键0
key_return = 1;
break;
case 0x1d:
{
if(key_times == 1 && Tcount
key_return = 2; //双击按键1
else
key_times++; //第一次按下,计数加1
}
break;
case 0x1b:
{
if(key_times == 2 && Tcount
key_return = 3; //三击按键2
else
key_times++; //第一次或第二次按下,计数加1
}
break;
case 0x17:
key_return = 4;
break;
case 0x27:
key_return = 5;
break;
case 0x2b:
key_return = 6;
break;
case 0x2d:
key_return = 7;
break;
case 0x2e:
key_return = 8;
break;
}
key_state++; // 转入等待按键释放状态
}
else
key_state--; // 两次列电平不同返回状态0,(消抖处理)
break;
case 2: //状态2功能:按键释放判定
P2 = 0x0f; // 行线全部输出低电平
P2 = 0x0f; // 重复送一次
if ( (P2 & 0x0f) == 0x0f)
key_state = 0; // 按键释放,返回状态0
break;
}
return key_return; //返回值
}
/******定时器1 定时1毫秒******************************************************************************/
void timer1(void) interrupt 3
{
TH1 = (65536-1000)/256;
TL1 = (65536-1000)%256;
if(++num == 10)
{keyread_flag = 1; //按键扫描允许标志位
num = 0;
}
}
/******定时器初始化**********************************************************************************/
void timer1_initial(void)
{
TH1 = (65536-1000)/256;
TL1 = (65536-1000)%256; //装初始值
IE = 0x88; //开总中断和定时器1中断
TMOD = 0x10; //工作方式1
TR1 = 1; //启动定时器
}
/******看门狗子程序*********************************************************************************/
void clr_wdt(void)
{
WDTRST=0x1e;
WDTRST=0xe1;
}
/******主程序****************************************************************************************/
main(void)
{
P0 = 0xff; //初始化LED端口
timer1_initial(); //定时器1初始化
while(1)
{
if(keyread_flag == 1) //矩阵扫描标志位允许
{
keyread_flag = 0;
clr_wdt(); //调用看门狗 (每2的14次方个机器周期内必须调用一次,使看门狗复位)
outdata = read_keyboard(); //读取矩阵键盘返回值
}
if(outdata == 1)
P0 = 0xaa; //单击按键0 点亮第1357个LED
else if(outdata == 2)
P0 = 0x55; //双击按键1 点亮第2468个LED
else if(outdata == 3)
P0 = 0x00; //三击按键2 点亮全部LED
}
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』