4x2矩阵按键的短按和长按


前言

最近在项目中遇到一个4x2矩阵按键的问题,各种百度了好久,都是在说4x4的矩阵按键(当然,通过4x4来推4x2的矩阵按键也没毛病),但是我现在的需求是识别出具体某个按键被按下后,是短按还是长按。
于是,我又找了好久,终于在阿B上找到了能满足我的需求的视频,按照上面所讲的结合我自己写的矩阵按键,终于实现了这个功能,在这里做个笔记。下面这个是阿B上的视频标题,通过搜索这个就能找到。
在这里插入图片描述


一、识别矩阵按键的具体按键

这里我用的是行列扫描法,由于我的6个IO口不是同一P引脚,所以我这里写了一个函数,方便对IO口赋值和对按键状态编码。
1、首先初始化6个IO引脚的工作模式为准双向模式
下面依次这样接了KEY_SET和BT_KEY
下面依次这样接了KEY_SET和BT_KEY]

void Key_Init(void)
{
	/***********************
	|  * 说明 *
	|  0,0准双向口
	|  0,1推挽输出
	|  1,0高阻输入
	|  1,1开漏
	************************/
	P6M1&=~(1<<0);P6M0&=~(1<<0);		/* KEY_SET P00*/
	P6M1&=~(1<<1);P6M0&=~(1<<1);		/* BT_KEY  P02*/
	P6M1&=~(1<<2);P6M0&=~(1<<2);		/* KEY0or1 P24*/
	P6M1&=~(1<<3);P6M0&=~(1<<3);		/* KEY_MOD P27*/
	P6M1&=~(1<<4);P6M0|=1<<4;			/* NetInto1 P37*/
	P6M1&=~(1<<5);P6M0|=1<<5;			/* NetInto2 P36*/	
}

2、写一个方便给6个IO口引脚赋值的函数

/*************************************************************************
* 函 数 名: Key_Pin
* 函数功能: 给按键引脚赋值0 or 1
* 输    入: p1-p4为高四位赋值,n2,n1为低四位的3,4为赋值
* 返 回 值: Key_Value的高四位为行按键的引脚值,低四位中的3,4位为列按键的引脚值
*************************************************************************/
uchar Key_Pin(uchar p1,uchar p2,uchar p3,uchar p4,uchar n1,uchar n2)
{
	uchar Key_Value=0x00,Key_PinValue[8]={0x00};
	KEY0or1=p1; KEY_MOD=p2; KEY_SET=p3; BT_KEY=p4; NetInto1=n1; NetInto2=n2;
	Key_PinValue[7]=KEY0or1; Key_PinValue[6]=KEY_MOD; Key_PinValue[5]=KEY_SET; Key_PinValue[4]=BT_KEY;
	Key_PinValue[3]=NetInto1; Key_PinValue[2]=NetInto2;
	Key_Value |= Key_PinValue[7]<<7;
	Key_Value |= Key_PinValue[6]<<6;
	Key_Value |= Key_PinValue[5]<<5;
	Key_Value |= Key_PinValue[4]<<4;
	Key_Value |= Key_PinValue[3]<<3;
	Key_Value |= Key_PinValue[2]<<2;
	Key_Value |= Key_PinValue[1]<<1;
	Key_Value |= Key_PinValue[0]<<0;
	return Key_Value;
}

3、按键扫描函数

/*************************************************************************
* 函 数 名: Key_Scan
* 函数功能: 检测有按键按下并读取键值
* 输    入: 无
* 返 回 值: KeyValue分别返回1~8
*************************************************************************/
uchar Key_Scan(void)
{
	uchar Key_PinSet=0, Key_PinSet_H=0, Key_PinSet_L=0, KeyValue=0;
	Key_PinSet = Key_Pin(0,0,0,0,1,1);       //0x0c
	if(Key_PinSet != 0x0c)    //读取按键是否按下
	{
		if(Key_PinSet != 0x0c)  //再次检测键盘是否按下
		{
			Key_PinSet_H = Key_Pin(0,0,0,0,1,1);   //0x0c 行输入0,检测列值,先判断列
			switch(Key_PinSet_H)
			{
				case(0X04):	KeyValue=1;break;		//4:0100
				case(0X08):	KeyValue=2;break;		//8:1000
			}
			
			Key_PinSet_L = Key_Pin(1,1,1,1,0,0);   //0xf0 列输入0,检测行值,判断行
			switch(Key_PinSet_L)
			{
				case(0X70):	KeyValue=KeyValue;break;
				case(0Xb0):	KeyValue=KeyValue+2;break;
				case(0Xd0): KeyValue=KeyValue+4;break;
				case(0Xe0):	KeyValue=KeyValue+6;break;
			}			
			
		}
	}
	return KeyValue;
}

二、识别具体按键的短按和长按

具体原理我也不太说的明白,直接上代码,不明白的话去看上面那个视频

//0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,
uint seg_num[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,0xee,0x3e,0x9c,0x7a,0x9e,0x8e,0x01,0x00};
uint ums,keytime;
uchar usec,keydly, keyold;
bit KEY_UP_Flag=0,KEY_MODE_Flag=0,KEY_RESET_Flag=0;
bit KEY_LANGUAGE_Flag=0,KEY_CUSTOM_Flag=0,KEY_TIME_Flag=0,KEY_DISANCE_Flag=0,KEY_RACESET_Flag=0;
bit KEY_UP_1S_Flag=0,KEY_RESET_1S_Flag=0;
//按键判断函数
void Key_Judgment(void)
{
	uchar keyval, keydown, keyup;			//keydown:按下标志, keyup:抬起标志
	if(keydly)return;		//按键判断函数10ms判断一次
	keydly = 1;
	keyval = Key_Scan();		
	keydown = keyval & (keyval^keyold);//按下的瞬间,keydown 有值
	keyup = ~keyval & (keyval^keyold);//抬起的瞬间,keyup 有值
	keyold = keyval;	//一直按着,keyold 有值
	if(keydown != 0)	//按下后对长按开始计时
	{
		keytime=ums;
		key_flag = 0;
	}
	if((keyup != 0)&&((ums-keytime)<=300))	//短按及抬起判断,按下后在300ms内若抬起,则视为短按
	{
		key_id = keyup;
	}
	if(key_flag==1 && keyup != 0)			//长按抬起判断,若长按完后还一直按着,则没反应,直到抬起,时间更新,进入下一次长按识别
	{	
		key_flag = 0;
		keytime=ums;
	}
	switch(keyold)							//长按标志,按下后一直到750-1000ms内不放手,则视为长按
	{
		case(2): 
			if((ums-keytime)>750 && (ums-keytime)<1000)
			{
				key_flag = 1;
				key_id = 9;	
			}			
			break;
		case(6): 
			if((ums-keytime)>750 && (ums-keytime)<1000)
			{
				key_flag = 1;
				key_id = 10;
			}
			break;
		default:
			if((ums-keytime)>750 && (ums-keytime)<1000)
			{
				key_flag = 1;
				key_id = 0;
			}
			break; 
	}
	
	switch(key_id)
	{
		case(1): KEY_LANGUAGE_Flag=1;break;	//1
		case(2): KEY_UP_Flag=1;break;		//8
		case(3): KEY_CUSTOM_Flag=1;break;	//2
		case(4): KEY_MODE_Flag=1;break;		//7
		case(5): KEY_TIME_Flag=1;break;		//3
		case(6): KEY_RESET_Flag=1;break;	//6
		case(7): KEY_DISANCE_Flag=1;break;	//4
		case(8): KEY_RACESET_Flag=1;break;	//5
		case(9): KEY_UP_1S_Flag=1;break;	//up_1s
		case(10): KEY_RESET_1S_Flag=1;break;//reset_1s
		default: break; 
	}
	key_id = 0;
	if(KEY_LANGUAGE_Flag == 1)			//1
	{
		KEY_LANGUAGE_Flag = 0;
		LED_FLI_D3(1);   				//用户指示灯D3闪烁1次
		SEG_Write_Data(seg_num[1],0);  //数码管显示
	}
	if(KEY_CUSTOM_Flag == 1)			//2
	{
		KEY_CUSTOM_Flag = 0;
		LED_FLI_D3(1);
		SEG_Write_Data(seg_num[2],1);  //数码管显示
	}
	if(KEY_TIME_Flag == 1)				//3
	{
		KEY_TIME_Flag = 0;
		LED_FLI_D3(1);
		SEG_Write_Data(seg_num[3],2);  //数码管显示
	}
	if(KEY_DISANCE_Flag == 1)			//4
	{
		KEY_DISANCE_Flag = 0;
		LED_FLI_D3(1);
		SEG_Write_Data(seg_num[4],3);  //数码管显示
	}

	if(KEY_RACESET_Flag== 1)			//5
	{
		KEY_RACESET_Flag = 0;
		LED_FLI_D3(1);					//用户指示灯D4闪烁1次
		SEG_Write_Data(seg_num[5],4);  //数码管显示
	}
	if(KEY_RESET_Flag == 1)				//6
	{
		KEY_RESET_Flag = 0;
		LED_FLI_D3(1);
		SEG_Write_Data(seg_num[6],5);  //数码管显示
	}
	if(KEY_MODE_Flag == 1)				//7
	{
		KEY_MODE_Flag = 0;
		LED_FLI_D3(1);
		SEG_Write_Data(seg_num[7],6);  //数码管显示
	}
	if(KEY_UP_Flag == 1)				//8
	{
		KEY_UP_Flag = 0;
		LED_FLI_D3(1);
		SEG_Write_Data(seg_num[8],7);  //数码管显示
	}
	if(KEY_UP_1S_Flag == 1)				//9
	{
		KEY_UP_1S_Flag = 0;
		LED_FLI_D4(1);
		SEG_Write_Data(seg_num[1],0);  //数码管显示
	}
	if(KEY_RESET_1S_Flag == 1)			//10
	{
		KEY_RESET_1S_Flag = 0;
		LED_FLI_D4(1);
		SEG_Write_Data(seg_num[1],2);  //数码管显示
	}
}

开定时器1,定时1ms

void Timer1_Init(void)		//1毫秒@11.0592MHz
{
	AUXR &= 0xBF;			//定时器时钟12T模式
	TMOD &= 0x0F;			//设置定时器模式
	TL1 = 0x66;				//设置定时初始值
	TH1 = 0xFC;				//设置定时初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
	ET1=1;	
}
void tml_isr() interrupt 3
{
	if(ums < 65536)
		ums++;
	else
		ums=0;
	if(++keydly==10)keydly=0;
}

总结

后面应该还能判断是双击、三击等多击事件,但我的项目上暂时没这个需求,所以先就不写了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键矩阵按键
好的,以下是一个简单的单片机矩阵键盘按的代码实现,以C语言为例: ```c #include <reg52.h> sbit key1 = P1^0; // 第1列第1行 sbit key2 = P1^1; // 第1列第2行 sbit key3 = P1^2; // 第1列第3行 sbit key4 = P1^3; // 第1列第4行 sbit key5 = P1^4; // 第2列第1行 sbit key6 = P1^5; // 第2列第2行 sbit key7 = P1^6; // 第2列第3行 sbit key8 = P1^7; // 第2列第4行 unsigned char key_value = 0; // 存储键值 unsigned char key_state = 0; // 按键状态,0表示未按下,1表示按下 unsigned char key_press_count = 0; // 按键计数器 unsigned char long_press_time = 50; // 按时间阈值,单位为10ms,即500ms void key_scan() // 扫描键盘 { if (key1 == 0 || key2 == 0 || key3 == 0 || key4 == 0 || key5 == 0 || key6 == 0 || key7 == 0 || key8 == 0) // 判断是否有按键按下 { key_state = 1; if (key_press_count < long_press_time) // 判断是否按 { key_press_count++; } else // 按 { key_value = 0xff; // 用0xff表示按事件 } } else // 没有按键按下 { if (key_state == 1) // 判断是否是按键松开 { key_state = 0; if (key_press_count < long_press_time) // 判断是否按 { key_value = key_press_count; // 用按键计数器的值表示键值 } key_press_count = 0; // 重置按键计数器 } } } void main() { while (1) { key_scan(); // 扫描键盘 if (key_value != 0) // 有按键按下 { // 进行相应的操作,比如控制LED灯亮灭 if (key_value == 1) // 按键1被按下 { P2 = 0x01; // 控制P2口的第1位为高电平,点亮LED1 } else if (key_value == 2) // 按键2被按下 { P2 = 0x02; // 控制P2口的第2位为高电平,点亮LED2 } else if (key_value == 0xff) // 按事件 { // 进行相应的操作 } key_value = 0; // 清空键值 } } } ``` 在上面的代码中,我们首先定义了8个按键对应的IO口,并定义了用于存储键值、按键状态和按键计数器的变量。然后在`key_scan()`函数中,我们通过判断各个按键对应的IO口是否为0,来判断是否有按键按下。如果有按键按下,我们将按键状态置为1,并判断按键计数器是否达到按时间阈值,如果未达到,则将按键计数器加1;如果达到,则将键值设为0xff,表示按事件。当所有按键都松开时,我们将按键状态置为0,并根据按键计数器的值来确定键值。最后,在`main()`函数中,我们通过判断键值来进行相应的操作,比如控制LED灯亮灭。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值