矩阵键盘KBD模板工程代码
其余功能在此基础上增加即可
该模板代码可实现矩阵键盘的单击,长按功能,双击功能
我称它为三位一体版矩阵键盘哈哈
(1)宏定义版本
#define SetKeyBoard(x) P4=(x>>3)|(x>>4);P3=x
#define GetKeyBoard() ((P4&0x10)<<3)|((P4&0x04)<<4)|(P3&0x3f)
#include "STC15F2K60S2.h"
#define u8 unsigned char
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2
#define key_state_3 3
#define key_state_4 4
#define NO_KEY 0
#define KEY_STATE_0 0
#define KEY_STATE_1 1
#define SetKeyBoard(x) P4=(x>>3)|(x>>4);P3=x
#define GetKeyBoard() ((P4&0x10)<<3)|((P4&0x04)<<4)|(P3&0x3f)
sbit buzzer=P0^6;
sbit relay=P0^4;
u8 code smg_duan[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};
u8 code smg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
u8 key_scan() //底层扫描函数
{
u8 key_temp,key_temporary=0;
u8 key1,key2;
SetKeyBoard(0x0f);
key1=GetKeyBoard();
SetKeyBoard(0xf0);
key2=GetKeyBoard();
key_temp=key1|key2;
switch(key_temp)
{
case NO_KEY:key_temporary=0;break;
case 0x77:key_temporary=4;break;
case 0x7b:key_temporary=5;break;
case 0x7d:key_temporary=6;break;
case 0x7e:key_temporary=7;break;
case 0xb7:key_temporary=8;break;
case 0xbb:key_temporary=9;break;
case 0xbd:key_temporary=10;break;
case 0xbe:key_temporary=11;break;
case 0xd7:key_temporary=12;break;
case 0xdb:key_temporary=13;break;
case 0xdd:key_temporary=14;break;
case 0xde:key_temporary=15;break;
case 0xe7:key_temporary=16;break;
case 0xeb:key_temporary=17;break;
case 0xed:key_temporary=18;break;
case 0xee:key_temporary=19;break;
case 0x99:key_temporary=200;break; //s10+s13
}
return key_temporary;
}
u8 key_long_short_click() //长短按判断函数
{
static unsigned char key_state=key_state_0,key_prev,key_time=0;
u8 key_val=0,key_return=0;
key_val=key_scan();
switch(key_state)
{
case key_state_0:
if(key_val!=NO_KEY)
{
key_state=key_state_1;
key_prev=key_val;
}
break;
case key_state_1:
if(key_val==NO_KEY)
{
key_state=key_state_0;
}
else
{
if(key_val==10)
{
key_state=key_state_4;
}
else
{
key_state=key_state_2;
key_time=0;
}
}
break;
case key_state_2:
if(key_val==NO_KEY) //short(短按)
{
key_state=key_state_0;
key_return=key_prev;
}
else
{
key_time++;
if(key_time>=50)
{
key_state=key_state_3;
key_return=key_val+100;
}
}
break;
case key_state_3: //松手检测判断
if(key_val==NO_KEY)
{
key_state=key_state_0;
}
break;
case key_state_4: //组合按键
if(key_val==NO_KEY)
{
key_state=key_state_0;
}
else
{
if(key_val!=10)
{
key_state=key_state_3;
key_return=key_val;
}
}
break;
}
return key_return;
}
u8 key_long_short_double_click() //双击判断函数
{
static unsigned char key_s=KEY_STATE_0,key_prev_1,key_time_1=0;
u8 key_val_1=0,key_return_1=0;
key_val_1=key_long_short_click();
switch(key_s)
{
case KEY_STATE_0:
if(key_val_1>0 && key_val_1<50)
{
key_s=KEY_STATE_1;
key_prev_1=key_val_1;
key_time_1=0;
}
else
{
key_return_1=key_val_1;
}
break;
case KEY_STATE_1:
if(key_val_1>0 && key_val_1<50)
{
key_s=KEY_STATE_0;
key_return_1=key_val_1+50;/*double(判断为双击)键值+50,和单机区别开*/
}
else
{
key_time_1++;
if(key_time_1>=50)
{
key_s=KEY_STATE_0;
key_return_1=key_prev_1;
}
}
break;
}
return key_return_1;
}
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
}
bit key_flag;
u8 count=100;
u8 count_display[8];
void main()
{
u8 keyvalue;
P2=0x80;P0=0xff;P2=0;
P2=0xa0;P0=0;P2=0;
Timer0Init();
while(1)
{
count_display[0]=smg_duan[count/100];
count_display[1]=smg_duan[count%100/10];
count_display[2]=smg_duan[count%10];
if(key_flag)
{
key_flag=0;
keyvalue=key_long_short_double_click();
switch(keyvalue)
{
case 4:
P2=0x80;P0=~0x01;P2=0;
count++;
break;
case 5:
P2=0x80;P0=~0x02;P2=0;
count--;
break;
case 54:
P2=0x80;P0=~0x10;P2=0;
count+=20;
break;
case 55:
P2=0x80;P0=~0x20;P2=0;
count-=20;
break;
case 104:
P2=0x80;P0=~0x04;P2=0;
count+=10;
break;
case 105:
P2=0x80;P0=~0x08;P2=0;
count-=10;
break;
case 200:
P2=0x80;P0=~0x80;P2=0;
count+=30;
break;
}
}
}
}
void timer0() interrupt 1
{
static unsigned int key_count=0,smg_count=0,i=0;
key_count++;
smg_count++;
if(key_count==10)
{
key_count=0;
key_flag=1;
}
if(smg_count==3)
{
smg_count=0;
P2=0xc0;P0=0;P2=0;
P2=0xe0;P0=~count_display[i];P2=0;
P2=0xc0;P0=smg_wei[i];P2=0;
i++;
if(i==8)i=0;
}
}
(2)普通版本
把底层扫描函数改成如下写法即可
u8 key_scan()
{
u8 key_temp,key_temporary=0;
u8 key1,key2;
P30=0;P31=0;P32=0;P33=0;P34=1;P35=1;P42=1;P44=1;
if(P44==0)key1=0x70;
if(P42==0)key1=0xb0;
if(P35==0)key1=0xd0;
if(P34==0)key1=0xe0;
if((P44==1)&&(P42==1)&&(P35==1)&&(P34==1))key1=0xf0;
P30=1;P31=1;P32=1;P33=1;P34=0;P35=0;P42=0;P44=0;
if(P33==0)key2=0x07;
if(P32==0)key2=0x0b;
if(P31==0)key2=0x0d;
if(P30==0)key2=0x0e;
if((P33==1)&&(P32==1)&&(P31==1)&&(P30==1))key2=0x0f;
key_temp=key1|key2;
switch(key_temp)
{
case NO_KEY:key_temporary=0;break;
case 0x77:key_temporary=4;break;
case 0x7b:key_temporary=5;break;
case 0x7d:key_temporary=6;break;
case 0x7e:key_temporary=7;break;
case 0xb7:key_temporary=8;break;
case 0xbb:key_temporary=9;break;
case 0xbd:key_temporary=10;break;
case 0xbe:key_temporary=11;break;
case 0xd7:key_temporary=12;break;
case 0xdb:key_temporary=13;break;
case 0xdd:key_temporary=14;break;
case 0xde:key_temporary=15;break;
case 0xe7:key_temporary=16;break;
case 0xeb:key_temporary=17;break;
case 0xed:key_temporary=18;break;
case 0xee:key_temporary=19;break; //s10+s12
case 0x95:key_temporary=200;break;
}
return key_temporary;
}
两种写法的比较:
(1)宏定义版本在我自己测试过程中,如果用到NE555,将P34和SIGNAL用连接子连上后,矩阵按键单击会没有松手检测功能。所以普通版本的实用性更高。
(2)普通版本不能实现双击功能,即使其他代码完全一致,仅仅改变底层扫面函数key_scan()的情况下。
以上两个问题大家可以自己实践,加以改进哦。