矩阵键盘(单击,长按,双击)

矩阵键盘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()的情况下。
以上两个问题大家可以自己实践,加以改进哦。

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值