蓝桥杯模块矩阵键盘Part_1

   九层妖塔 起于垒土
在这里插入图片描述

矩阵键盘

一、理论

1、矩阵键盘的识别与编码:

step1:判断键盘中有无按键按下
  因为矩阵键盘的接口中只有四个行线是在一组I/O口上的,为了便于识别,所以将行拉高,列拉低 若四个行线不全为高电平,则表示有按键按下。
step2:判断闭合按键的所在的位置
  在确认有按键按下后,即可进入确定具体闭合键的过程。
  ①扫描法:依次将行线置为低电平即在置某根行线为低电平时,其他线全为高电平。再逐个检查列线的状态。
  ②反转法:行全扫描,读取列码;列全扫描,读取行码。将行、列码组合在一起,得到按键的键码。
step3:根据闭合键的键码,采用查表法或者计算法得到自定义的键值。

2、矩阵键盘的工作方式:

①查询扫描
  把键盘扫描子程序和其他子程序并列在一起,单片机循环分时运行各个子程序。当按键按下并且单片机查询到的时候立即响应键盘输入操作。
②定时扫描
  定时器,灵活多样,方法较多。
③中断扫描
  依赖于硬件(如四路与门等),利用外部中断。

二、原理图

在这里插入图片描述

三、Template1

Template1使用状态机的方法进行按键的扫描识别,用定时器来替代软件延时,没必要纠结于反转法还是行扫描法。
无法实现长按短按以及多个同时按下的识别,但写法较为简单,适用于要求较少的情况。
来自国信长天官方电子版例程的改编。

1、矩阵键盘扫描函数:

//--------------------------矩阵键盘扫描--读取矩阵键盘键值--------------//        
void keyscan16(void)         //每隔10ms扫描一次
{
	static uchar hang;  //行
	static uchar key_state=0;
	
	if(key_flag==1)key_flag = 0;
	else return;
		
	switch(key_state)
	{
		case 0:
		{
			P44=0;P42=0;P3=0X0F;  //行拉高,列拉低
			if(P3 != 0X0F)   //有按键按下
			key_state=1;
		}break;
		
		case 1:
		{
			P44=0;P42=0;P3=0X0F;  //行拉高,列拉低
			if(P3 != 0X0F)   //有按键按下
			{
				if(P30 == 0) hang = 1;
				if(P31 == 0) hang = 2;
				if(P32 == 0) hang = 3;
				if(P33 == 0) hang = 4;//确定列
				switch(hang)
				{
					case 1:
					{
						P44=1;P42=1;P3=0XF0;  //列拉高,行拉低
						if(P44 == 0) {key_value=7;key_state=2;}        //S7
						else if(P42 == 0) {key_value=11;key_state=2;}  //S11
						else if(P35 == 0) {key_value=15;key_state=2;}  //S15
						else if(P34 == 0) {key_value=19;key_state=2;}  //S19
					}break;
					
					case 2:
					{
						P44=1;P42=1;P3=0XF0;  //列拉高,行拉低
						if(P44 == 0) {key_value=6;key_state=2;}         //S6
						else if(P42 == 0) {key_value=10;key_state=2;}   //S10
						else if(P35 == 0) {key_value=14;key_state=2;}	//S14
						else if(P34 == 0) {key_value=18;key_state=2;}   //S18
					}break;
					
					case 3:
					{
						P44=1;P42=1;P3=0XF0;  //列拉高,行拉低
						if(P44 == 0) {key_value=5;key_state=2;}			 //S5
						else if(P42 == 0) {key_value=9;key_state=2;}	 //S9
						else if(P35 == 0) {key_value=13;key_state=2;}    //S13
						else if(P34 == 0) {key_value=17;key_state=2;}	 //S17
					}break;
					
					case 4:
					{
						P44=1;P42=1;P3=0XF0;  //列拉高,行拉低
						if(P44 == 0) {key_value=4;key_state=2;}         //S4
						else if(P42 == 0) {key_value=8;key_state=2;}    //S8
						else if(P35 == 0) {key_value=12;key_state=2;}   //S12
						else if(P34== 0) {key_value=16;key_state=2;}    //S16
					} break;				
				}
			}
			else
			{
				key_state=0;	
			}
		}break;
		
		case 2:
		{
			P44=0;P42=0;P3=0X0F;  //行拉高,列拉低
			if(P3 == 0X0F) //按键放开
			 key_state=0;
		}break;
	}

}

2、定时器初始化及定时器服务函数:

//----------------------------定时器1服务函数,数码管显示&按键消抖----------------//
void Timer1_Service()  
{
	static uchar in_T1=0;  //1ms定时器T1计满溢出的次数
	
	TR1 = 1;		   //定时器1开始计时
	
	if(TF1 == 1)   //TF1为1,1ms定时时间已到
	{
		Timer1Init();  //关定时器;重装初值;清除TF1标志
		SEG_Disp(SEG_Code,SEG_Position);  //动态数码管显示,1ms执行一次
		if(++SEG_Position == 8) SEG_Position=0;
		
		if(++in_T1 == 10)
		{
			in_T1=0;
			key_flag = 1;  //10ms按键扫描标志位置1
		}
		
		TR1 = 1;		//定时器1开始计时
	}
}

//------------------------------------定时器1初始化,------------//
void Timer1Init(void)		//1毫秒@12.000MHz
{
	TR1 = 0;					//关定时器1
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x20;		//设置定时初值
	TH1 = 0xD1;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	//TR1 = 1;		//定时器1开始计时
}

3、部分主程序:

bit key_flag = 0;       //按键10ms扫描标志位       
uchar key_value=0;      //按键值

void main(void)
{
	All_Init();
	Timer1Init();		//1毫秒@12.000MHz定时器1初始化

	while(1)
	{
		keyscan16();
		sprintf(SEG_Buf,"%04u",(uint)key_value);
		SEG_Tran(SEG_Buf,SEG_Code);   //动态数码管显示转换
		Timer1_Service();             //定时器1服务函数,数码管显示
	}
}

4、Notes:

 ●key_flag按键扫描标志位,初始值为0。
  ○在定时器服务函数Timer1_Service()中定时10ms到key_flag被置1;
  ○进入矩阵键盘扫描函数keyscan16()中先判断key_flag是否为1,若为1则先将key_flag置0再继续执行,若为0则跳出。
  ○key_flag按键扫描标志位保证了10ms进行一次按键扫描

 ●矩阵键盘扫描函数keyscan16()每10ms执行一次按键扫描,子函数里的静态局部变量按键状态 key_state有0,1,2三个值,初始值为0。
  ○一次按键识别要进行三次按键扫描。
  ○ key_state为0表示本次按键识别还未开始。10ms到进行第一次按键扫描,有无按键按下,若检测到低电平,将key_state置1,表示又可能有按键按下;若无低电平,则继续保持为0,等待下一个10ms。
  ○ key_state为1表示已经扫描到一次低电平。10ms到进行第二次按键扫描,先检测有无按键按下,若检测到低电平就继续进行按键值的判断,并将key_state置为2;若没检测到低电平,则将 key_state置零,本次按键识别结束。
  ○ key_state为2表示已经进行完按键是否按下和具体按键键值的判断,进行松手检测,防止重入。若按键以放开,将key_state置0,本次按键识别结束。

 ●定时器溢出响应依旧使用的是查询法,担心如果用中断法响应定时器溢出,会对其他部分产生影响。自拟了一个定时器服务子函数Timer1_Service(),通过查询定时器1的溢出标志位TF1来决定是否进入定时器服务子函数Timer1_Service()。使用静态局部变量in_T1来判断计时溢出的次数,10次时,10ms时间到。实现数码管和按键公用一个定时器。

 ●采用状态法进行按键识别扫描,系统实时性好,且每10ms扫描可以防止抖动。

 ●无法实现长按短按以及多个同时按下的识别,但写法较为简单。
 ●来源于国信长天的电子版例程,原为中断法响应定时器溢出,改为查询标志位法。还有其他细节和习惯的修改。

附、按键的识别方法_状态法进行按键扫描_流程图|状态转换图

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

#法外狂徒张三

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值