单片机学习笔记————51单片机实现矩阵键盘的组合按键触发

一、使用proteus绘制简单的电路图,用于后续仿真

单片机学习笔记————51单片机实现矩阵键盘的组合按键触发_第1张图片

 

二、编写程序

/********************************************************************************************************************
----	@Project:	Matrix-KEY
----	@File:	main.c
----	@Edit:	ZHQ
----	@Version:	V1.0
----	@CreationTime:	20200514
----	@ModifiedTime:	20200514
----	@Description:	16个按键中,每按一个按键都能触发一次蜂鸣器发出“滴”的一声。在同时按下S1和S16按键时,将会点亮一个LED灯。在同时按下S4和S13按键时,将会熄灭一个LED灯。
----	单片机:AT89C52
********************************************************************************************************************/
#include "reg52.h"
/*——————宏定义——————*/
#define FOSC 11059200L
#define T1MS (65536-FOSC/12/1000)   /*1ms timer calculation method in 12Tmode*/

#define const_voice_short  80   /*蜂鸣器短叫的持续时间*/

/* 
*  注意:组合按键的去抖动延时const_key_time_comb千万不能等于单击按键
*  的去抖动延时const_key_time,否则组合按键会覆盖单击按键的触发。
*/
#define const_key_time  24    /*按键去抖动延时的时间*/
#define const_key_time_comb  28    /*组合按键去抖动延时的时间*/
/*——————变量函数定义及声明——————*/
/*行*/
sbit Key1 = P0^0;	/*第一行输入*/
sbit Key2 = P0^1;	/*第二行输入*/
sbit Key3 = P0^2;	/*第三行输入*/
sbit Key4 = P0^3;	/*第四行输入*/

/*列*/
sbit Key5 = P0^4;	/*第一列输入*/
sbit Key6 = P0^5;	/*第二列输入*/
sbit Key7 = P0^6;	/*第三列输入*/
sbit Key8 = P0^7;	/*第四列输入*/

/*定义蜂鸣器*/
sbit BUZZER = P2^7;

/*LED灯*/
sbit LED = P3^5;

unsigned char ucKeyStep = 1;   /*按键扫描步骤变量*/

unsigned char ucKeySec = 0;   /*被触发的按键编号*/

unsigned int  uiKeyTimeCnt[16] = 0; /*16个按键去抖动延时计数器*/
unsigned char ucKeyLock[16] = 0; /*16按键触发后自锁的变量标志*/

unsigned int  uiKeyTimeCnt_01_16 = 0; /*S1和S16组合按键去抖动延时计数器*/
unsigned char ucKeyLock_01_16 = 0; /*S1和S16组合按键触发后自锁的变量标志*/

unsigned int  uiKeyTimeCnt_04_13 = 0; /*S4和S13组合按键去抖动延时计数器*/
unsigned char ucKeyLock_04_13 = 0; /*S4和S13组合按键触发后自锁的变量标志*/

unsigned char ucRowRecord = 1; /*记录当前扫描到第几列了*/

unsigned int  uiVoiceCnt = 0;  /*蜂鸣器鸣叫的持续时间计数器*/

unsigned int	uiKeyStatus = 0xffff;	/*此变量每一位代表一个按键的状态,共16个按键。1代表没有被按下,0代表被按下。*/

/**
* @brief  定时器0初始化函数
* @param  无
* @retval 初始化T0
**/
void Init_T0(void)
{
	TMOD = 0x01;                    /*set timer0 as mode1 (16-bit)*/
	TL0 = T1MS;                     /*initial timer0 low byte*/
	TH0 = T1MS >> 8;                /*initial timer0 high byte*/
}
/**
* @brief  外围初始化函数
* @param  无
* @retval 初始化外围
**/
void Init_Peripheral(void)
{
	ET0 = 1;/*允许定时中断*/
	TR0 = 1;/*启动定时中断*/
	EA = 1;/*开总中断*/

}

/**
* @brief  初始化函数
* @param  无
* @retval 初始化单片机
**/
void	Init(void)
{
	BUZZER = 1;	
	LED = 0;
	Init_T0();
}
/**
* @brief  扫描按键函数
* @param  无
* @retval 详细过程:
*  第一步:先把16个按键翻译成独立按键。
*  第二步: 再按独立按键的去抖动方式进行按键识别。
**/
void Key_Scan(void)
{
	switch(ucKeyStep)
	{
		case 1:	/*把16个按键的状态快速记录在uiKeyStatus变量的每一位中,相当于把矩阵键盘翻译成独立按键。*/
			for(ucRowRecord = 1; ucRowRecord < 5; ucRowRecord ++)
			{
				if(ucRowRecord == 1)	/*第一列输出低电平*/
				{
					Key5 = 0;
					Key6 = 1;
					Key7 = 1;
					Key8 = 1;
					/*如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态*/
					if(Key1 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xfffe;	/*S1*/
					}
					if(Key2 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xffef;	/*S5*/
					}
					if(Key3 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xfeff;	/*S9*/
					}
					if(Key4 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xefff;	/*S13*/
					}
				}
				else if(ucRowRecord == 2)	/*第二列输出低电平*/
				{
					Key5 = 1;
					Key6 = 0;
					Key7 = 1;
					Key8 = 1;
					/*如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态*/
					if(Key1 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xfffd;	/*S2*/
					}
					if(Key2 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xffdf;	/*S6*/
					}
					if(Key3 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xfdff;	/*S10*/
					}
					if(Key4 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xdfff;	/*S14*/
					}
				}
				else if(ucRowRecord == 3)	/*第三列输出低电平*/
				{
					Key5 = 1;
					Key6 = 1;
					Key7 = 0;
					Key8 = 1;
					/*如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态*/
					if(Key1 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xfffb;	/*S3*/
					}
					if(Key2 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xffbf;	/*S7*/
					}
					if(Key3 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xfbff;	/*S11*/
					}
					if(Key4 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xbfff;	/*S15*/
					}
				}
				else /*第四列输出低电平*/
				{
					Key5 = 1;
					Key6 = 1;
					Key7 = 1;
					Key8 = 0;
					/*如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态*/
					if(Key1 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xfff7;	/*S4*/
					}
					if(Key2 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xff7f;	/*S8*/
					}
					if(Key3 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0xf7ff;	/*S12*/
					}
					if(Key4 == 0)
					{
						uiKeyStatus = uiKeyStatus & 0x7fff;	/*S16*/
					}
				}
			}
			ucKeyStep = 2;	/*切换到下一个运行步骤*/
		break;
		case 2:	/*像独立按键一样进行去抖动和翻译。*/
			if((uiKeyStatus & 0x0001) == 0x0001)	/*说明1号键没有被按下来*/
			{
				uiKeyTimeCnt[0] = 0;
				ucKeyLock[0] = 0;
			}
			else if(ucKeyLock[0] == 0)
			{
				uiKeyTimeCnt[0] ++;
				if(uiKeyTimeCnt[0] > const_key_time)
				{
					uiKeyTimeCnt[0] = 0;
					ucKeyLock[0] =1;
					ucKeySec = 1;
				}
			}
			
			if((uiKeyStatus & 0x0002) == 0x0002)	/*说明2号键没有被按下来*/
			{
				uiKeyTimeCnt[1] = 0;
				ucKeyLock[1] = 0;
			}
			else if(ucKeyLock[1] == 0)
			{
				uiKeyTimeCnt[1] ++;
				if(uiKeyTimeCnt[1] > const_key_time)
				{
					uiKeyTimeCnt[1] = 0;
					ucKeyLock[1] =1;
					ucKeySec = 2;
				}
			}
			
			if((uiKeyStatus & 0x0004) == 0x0004)	/*说明3号键没有被按下来*/
			{
				uiKeyTimeCnt[2] = 0;
				ucKeyLock[2] = 0;
			}
			else if(ucKeyLock[2] == 0)
			{
				uiKeyTimeCnt[2] ++;
				if(uiKeyTimeCnt[2] > const_key_time)
				{
					uiKeyTimeCnt[2] = 0;
					ucKeyLock[2] =1;
					ucKeySec = 3;
				}
			}
			
			if((uiKeyStatus & 0x0008) == 0x0008)	/*说明4号键没有被按下来*/
			{
				uiKeyTimeCnt[3] = 0;
				ucKeyLock[3] = 0;
			}
			else if(ucKeyLock[3] == 0)
			{
				uiKeyTimeCnt[3] ++;
				if(uiKeyTimeCnt[3] > const_key_time)
				{
					uiKeyTimeCnt[3] = 0;
					ucKeyLock[3] =1;
					ucKeySec = 4;
				}
			}
			
			if((uiKeyStatus & 0x0010) == 0x0010)	/*说明5号键没有被按下来*/
			{
				uiKeyTimeCnt[4] = 0;
				ucKeyLock[4] = 0;
			}
			else if(ucKeyLock[4] == 0)
			{
				uiKeyTimeCnt[4] ++;
				if(uiKeyTimeCnt[4] > const_key_time)
				{
					uiKeyTimeCnt[4] = 0;
					ucKeyLock[4] =1;
					ucKeySec = 5;
				}
			}
			
			if((uiKeyStatus & 0x0020) == 0x0020)	/*说明6号键没有被按下来*/
			{
				uiKeyTimeCnt[5] = 0;
				ucKeyLock[5] = 0;
			}
			else if(ucKeyLock[5] == 0)
			{
				uiKeyTimeCnt[5] ++;
				if(uiKeyTimeCnt[5] > const_key_time)
				{
					uiKeyTimeCnt[5] = 0;
					ucKeyLock[5] =1;
					ucKeySec = 6;
				}
			}
			
			if((uiKeyStatus & 0x0040) == 0x0040)	/*说明7号键没有被按下来*/
			{
				uiKeyTimeCnt[6] = 0;
				ucKeyLock[6] = 0;
			}
			else if(ucKeyLock[6] == 0)
			{
				uiKeyTimeCnt[6] ++;
				if(uiKeyTimeCnt[6] > const_key_time)
				{
					uiKeyTimeCnt[6] = 0;
					ucKeyLock[6] =1;
					ucKeySec = 7;
				}
			}
			
			if((uiKeyStatus & 0x0080) == 0x0080)	/*说明8号键没有被按下来*/
			{
				uiKeyTimeCnt[7] = 0;
				ucKeyLock[7] = 0;
			}
			else if(ucKeyLock[7] == 0)
			{
				uiKeyTimeCnt[7] ++;
				if(uiKeyTimeCnt[7] > const_key_time)
				{
					uiKeyTimeCnt[7] = 0;
					ucKeyLock[7] =1;
					ucKeySec = 8;
				}
			}
			
			if((uiKeyStatus & 0x0100) == 0x0100)	/*说明9号键没有被按下来*/
			{
				uiKeyTimeCnt[8] = 0;
				ucKeyLock[8] = 0;
			}
			else if(ucKeyLock[8] == 0)
			{
				uiKeyTimeCnt[8] ++;
				if(uiKeyTimeCnt[8] > const_key_time)
				{
					uiKeyTimeCnt[8] = 0;
					ucKeyLock[8] =1;
					ucKeySec = 9;
				}
			}
			
			if((uiKeyStatus & 0x0200) == 0x0100)	/*说明10号键没有被按下来*/
			{
				uiKeyTimeCnt[9] = 0;
				ucKeyLock[9] = 0;
			}
			else if(ucKeyLock[9] == 0)
			{
				uiKeyTimeCnt[9] ++;
				if(uiKeyTimeCnt[9] > const_key_time)
				{
					uiKeyTimeCnt[9] = 0;
					ucKeyLock[9] =1;
					ucKeySec = 10;
				}
			}
			
			if((uiKeyStatus & 0x0400) == 0x0400)	/*说明11号键没有被按下来*/
			{
				uiKeyTimeCnt[10] = 0;
				ucKeyLock[10] = 0;
			}
			else if(ucKeyLock[10] == 0)
			{
				uiKeyTimeCnt[10] ++;
				if(uiKeyTimeCnt[10] > const_key_time)
				{
					uiKeyTimeCnt[10] = 0;
					ucKeyLock[10] =1;
					ucKeySec = 11;
				}
			}
			
			if((uiKeyStatus & 0x0800) == 0x0800)	/*说明12号键没有被按下来*/
			{
				uiKeyTimeCnt[11] = 0;
				ucKeyLock[11] = 0;
			}
			else if(ucKeyLock[11] == 0)
			{
				uiKeyTimeCnt[11] ++;
				if(uiKeyTimeCnt[11] > const_key_time)
				{
					uiKeyTimeCnt[11] = 0;
					ucKeyLock[11] =1;
					ucKeySec = 12;
				}
			}
			
			if((uiKeyStatus & 0x1000) == 0x1000)	/*说明13号键没有被按下来*/
			{
				uiKeyTimeCnt[12] = 0;
				ucKeyLock[12] = 0;
			}
			else if(ucKeyLock[12] == 0)
			{
				uiKeyTimeCnt[12] ++;
				if(uiKeyTimeCnt[12] > const_key_time)
				{
					uiKeyTimeCnt[12] = 0;
					ucKeyLock[12] =1;
					ucKeySec = 13;
				}
			}
			
			if((uiKeyStatus & 0x2000) == 0x2000)	/*说明14号键没有被按下来*/
			{
				uiKeyTimeCnt[13] = 0;
				ucKeyLock[13] = 0;
			}
			else if(ucKeyLock[13] == 0)
			{
				uiKeyTimeCnt[13] ++;
				if(uiKeyTimeCnt[13] > const_key_time)
				{
					uiKeyTimeCnt[13] = 0;
					ucKeyLock[13] =1;
					ucKeySec = 14;
				}
			}
			
			if((uiKeyStatus & 0x4000) == 0x4000)	/*说明15号键没有被按下来*/
			{
				uiKeyTimeCnt[14] = 0;
				ucKeyLock[14] = 0;
			}
			else if(ucKeyLock[14] == 0)
			{
				uiKeyTimeCnt[14] ++;
				if(uiKeyTimeCnt[14] > const_key_time)
				{
					uiKeyTimeCnt[14] = 0;
					ucKeyLock[14] =1;
					ucKeySec = 15;
				}
			}
			
			if((uiKeyStatus & 0x8000) == 0x8000)	/*说明16号键没有被按下来*/
			{
				uiKeyTimeCnt[15] = 0;
				ucKeyLock[15] = 0;
			}
			else if(ucKeyLock[15] == 0)
			{
				uiKeyTimeCnt[15] ++;
				if(uiKeyTimeCnt[15] > const_key_time)
				{
					uiKeyTimeCnt[15] = 0;
					ucKeyLock[15] =1;
					ucKeySec = 16;
				}
			}
			
			if((uiKeyStatus & 0x8001) == 0x0000)	/*S1和S16的组合键盘被按下。*/
			{
				if(ucKeyLock_01_16 == 0)
				{
					uiKeyTimeCnt_01_16 ++;
					if(uiKeyTimeCnt_01_16 > const_key_time_comb)
					{
						uiKeyTimeCnt_01_16 = 0;
						ucKeyLock_01_16 = 1;
						ucKeySec = 17;
					}
				}
			}	
			else
				{
					uiKeyTimeCnt_01_16 = 0; /*S1和S16组合按键去抖动延时计数器*/
					ucKeyLock_01_16 = 0; /*S1和S16组合按键触发后自锁的变量标志*/
				}
			
			if((uiKeyStatus & 0x1008) == 0x0000)	/*S4和S13的组合键盘被按下。*/
			{
				if(ucKeyLock_04_13 == 0)
				{
					uiKeyTimeCnt_04_13 ++;
					if(uiKeyTimeCnt_04_13 > const_key_time_comb)
					{
						uiKeyTimeCnt_04_13 = 0;
						ucKeyLock_04_13 = 1;
						ucKeySec = 18;
					}
				}
			}	
			else
				{
					uiKeyTimeCnt_04_13 = 0; /*S4和S13组合按键去抖动延时计数器*/
					ucKeyLock_04_13 = 0; /*S4和S13组合按键触发后自锁的变量标志*/
				}
			uiKeyStatus = 0xffff;	/*及时恢复状态,方便下一次扫描*/
			ucKeyStep = 1;	/*返回到第一个运行步骤重新开始扫描*/
		break;		
	}
}
/**
* @brief  按键服务函数
* @param  无
* @retval 根据扫描得到的值,进行数据处理
**/
void key_Service(void)
{
	switch(ucKeySec)
	{
		case 1: /*1号键*/
		case 2: /*2号键*/
		case 3: /*3号键*/
		case 4: /*4号键*/
		case 5: /*5号键*/
		case 6: /*6号键*/			
		case 7: /*7号键*/
		case 8: /*8号键*/
		case 9: /*9号键*/
		case 10: /*10号键*/
		case 11: /*11号键*/
		case 12: /*12号键*/
		case 13: /*13号键*/
		case 14: /*14号键*/
		case 15: /*15号键*/										
		case 16: /*16号键*/
			uiVoiceCnt = const_voice_short;	/*按键声音触发,滴一声就停。*/
			ucKeySec = 0;	/*响应按键服务处理程序后,按键编号清零,避免一致触发*/
		break;
		case 17:
			LED = 1;
			uiVoiceCnt = const_voice_short;
			ucKeySec = 0;
		break;
		case 18:
			LED = 0;
			uiVoiceCnt = const_voice_short;
			ucKeySec = 0;
		break;		
	}
}
/**
* @brief  定时器0中断函数
* @param  无
* @retval 无
**/
void ISR_T0(void)	interrupt 1
{
	TF0 = 0;  /*清除中断标志*/
  TR0 = 0; /*关中断*/
	/*扫描按键*/
	Key_Scan();
	if(0 != uiVoiceCnt)
	{
		uiVoiceCnt --;
		BUZZER = 0;
	}
	else
	{
		BUZZER = 1;
	}
	
	TL0 = T1MS;                     /*initial timer0 low byte*/
	TH0 = T1MS >> 8;                /*initial timer0 high byte*/
  TR0 = 1; /*开中断*/	
}
/**
* @brief  延时函数
* @param  无
* @retval 无
**/
void Delay_Long(unsigned int uiDelayLong)
{
   unsigned int i;
   unsigned int j;
   for(i=0;i

 

三、仿真实现

单片机学习笔记————51单片机实现矩阵键盘的组合按键触发_第2张图片

 

你可能感兴趣的:(单片机,proteus,C,51单片机,矩阵键盘,组合按键)