目录
1.矩阵键盘简介
2.获取矩阵键盘键码值
3.矩阵键盘实现密码锁
1.矩阵键盘简介
矩阵键盘就是一个基于独立按键的Plus版本,它的原理图就是下面这样:
和独立按键就像表兄弟一样,为什么这么说呢?因为这个矩阵键盘上可以找到很多独立按键的影子,比如这个独立按键的原理图:
就是一端接地了,其他的没有什么区别,我们使用这个矩阵键盘可以参照我们的独立按键的使用。
矩阵键盘的使用又有点我们的数码管显示的感觉,就是数码管使用循环显示各个数位上的数字,使这个间隔无限短以至于我们的数字可以在同一时间显示,我们的这个矩阵键盘也是差不多的,就是使用循环扫描行/列,然后在另外一边判断按键按下情况,从而推断出到底是哪个按键按下,这样我们的接口就从4x4变成了4+4,大大减少了IO口的占用。
循环是怎么循环的呢?我们在使用独立按键的时候是相当于一排独立按键,我们把它们的一端都连接起来并接地,然后再在另外一边设置IO口,然后我们通过判断IO口来判断具体是哪个按键按下;这里矩阵键盘也是类似的,我们想要使用第一行的某个按键,我们就把第一行它们的共同连接”模拟接地“,就是设置为0,然后再在另外一边列的四个IO口判断哪个按键按下,如果还要判断你整个键盘不知道哪个按键的话,我们只需要循环把每一行的IO口置为0,然后判断,只要我们的循环速度足够快,我们就可以检测到任意位置的按键按下情况,我们的电脑键盘也是基于这样的底层原理,只是加了很多复杂的优化。
2.获取矩阵键盘键码值
矩阵键盘一共有16个键盘按键,从s1到s16,我们使用循环读取来获得每个按键的键码值。和独立按键一样的是,我们还需要要使用消抖操作来防止出错,使用循环确保按键留在函数内部,只是多了循环和读取并返回键码值的过程。
由于引脚有限,我们的共用IO口的情况是存在的,所以我们循环把行(P14到P17)置为0就会间接导致我们的蜂鸣器响,所以我们最好使用列的扫描来实现按键检测。
这里就是函数的实现:
int Key()
{P1 = 0xff;P1_3 = 0;if(P1_7 == 0){Delay(20);while(P1_7 == 0);Delay(20);return 1;}if(P1_6 == 0){Delay(20);while(P1_6 == 0);Delay(20);return 5;}if(P1_5 == 0){Delay(20);while(P1_5 == 0);Delay(20);return 9;}if(P1_4 == 0){Delay(20);while(P1_4 == 0);Delay(20);return 13;}P1 = 0xff;P1_2 = 0;if(P1_7 == 0){Delay(20);while(P1_7 == 0);Delay(20);return 2;}if(P1_6 == 0){Delay(20);while(P1_6 == 0);Delay(20);return 6;}if(P1_5 == 0){Delay(20);while(P1_5 == 0);Delay(20);return 10;}if(P1_4 == 0){Delay(20);while(P1_4 == 0);Delay(20);return 14;}P1 = 0xff;P1_1 = 0;if(P1_7 == 0){Delay(20);while(P1_7 == 0);Delay(20);return 3;}if(P1_6 == 0){Delay(20);while(P1_6 == 0);Delay(20);return 7;}if(P1_5 == 0){Delay(20);while(P1_5 == 0);Delay(20);return 11;}if(P1_4 == 0){Delay(20);while(P1_4 == 0);Delay(20);return 15;}P1 = 0xff;P1_0 = 0;if(P1_7 == 0){Delay(20);while(P1_7 == 0);Delay(20);return 4;}if(P1_6 == 0){Delay(20);while(P1_6 == 0);Delay(20);return 8;}if(P1_5 == 0){Delay(20);while(P1_5 == 0);Delay(20);return 12;}if(P1_4 == 0){Delay(20);while(P1_4 == 0);Delay(20);return 16;}return 0;
}
这里主要思路就是先把所有位置为高电平1,然后循环把列置为0,再判断每行获取按键的坐标,然后把按键值返回。这样就获取了按键键码。
我们再使用前面使用的矩阵键盘的代码用来调试我们的获取键码值的代码:
#include "LCD1602.h"
#include "MatrixKey.h"void main()
{int num = 0;while(1){num = Key();if(num){LCD_Init();LCD_ShowNum(1,1,num,2);}}
}
这样我们就可以实现这个键码值的获取和显示了,有一点要注意的是,这里的if(num)判断条件是不能去掉的,因为我们如果没有这个条件的话,函数的返回值就默认是0,就算我们按下了按键,我们的显示屏可能那一刻显示出了对应键码值,但是一瞬间又会被这个键码值0刷新,所以我们需要加上这个判断条件来确保我们的显示稳定可靠。
3.矩阵键盘实现密码锁
我们可以用一个小项目增加我们对矩阵键盘的理解:使用矩阵键盘1到9代表数字1到9,按键10代表数字0,按键11和按键12分别代表确认和删除,按键13代表清零,其他的按键就不作处理,并且按下无效。
这样我们就可以开始我们的思路:
我们想要制作一个密码锁,最重要的就是用户输入,我们可以使用四位输入,获取一个最大位4位的数,然后判断我们的输入是不是和这个密码一样,如果一样就输出True否则输出ERR。但是,这个是我的老师——UP江协科技教我的
我需要一个更为接近真实的密码输入,所以我决定采用六位密码,并且不打算使用一个长的数来得到我的输入,我想要使用一个一个的数值填入一个字符串数组,这样我们就可以在我们原本的代码上更改,可以实现更复杂更长的密码,不会受到限制。原版的老师教的输入是从最后一位像是一点点插入进输出框的,这里我也要做一点更改,就把初始界面设置为******,然后我们输入一个数字就会填充并取代一个*,还可以使用键11确认并核验密码,键12删除最后一位的值,用键13把所有输入清零。
#include "LCD1602.h"
#include "MatrixKey.h"
#include <stdio.h>
#include <string.h>
void Delay(unsigned int xms);void MyLock()
{int count = 0;int GetNum = 0;char Input[7] = "******";char PassWord[7]="123456";LCD_ShowString(1,1,Input);while(1){LCD_ShowString(1,1,"PassWord:");LCD_ShowString(1,10,Input);Delay(1);//ÔöÇ¿ÏÔʾGetNum =Key();//»ñÈ¡¼üÖµif(GetNum && GetNum<=10){GetNum%=10;if(count<6){sprintf(Input+count,"%d",GetNum);//дÈëLCD_ShowString(1,10,Input);count++;}else//³¬³ö·¶Î§{LCD_ShowString(2,12," ");//Çå¿Õ״̬À¸LCD_ShowString(2,12,"FULL");//״̬À¸}}else if(GetNum==11)//È·Èϼü{if(strcmp(Input,PassWord) == 0)//Input == PassWord{LCD_ShowString(2,12," ");//Çå¿Õ״̬À¸LCD_ShowString(2,12,"RIGHT");//״̬À¸}else{LCD_ShowString(2,12," ");//Çå¿Õ״̬À¸LCD_ShowString(2,12,"ERROR");//״̬À¸}}else if(GetNum == 12)//ɾ³ý¼ü{if(count)//È·±£ÓÐÊý×Ö{count--;Input[count]='*';LCD_ShowString(2,12," ");//Çå¿Õ״̬À¸}}else if(GetNum == 13)//ÇåÁã¼ü{strcpy(Input,"******");count = 0;}}
}void main()
{LCD_Init();while(1){MyLock();}
}
这里有几个比较重要的点:
- 我们的头文件引用最好在c文件中,而且这个自定义的头文件只能使用一次,不然会显示函数未定义的报错。假设我们定义了A.h,而这个头文件里又包含了别的头文件,但是我们使用A.c或者B.c或者B.h都是不能使用A.h里包含的头文件的
- 还有就是上一节讲到的函数在多个c文件中使用的话,我们无法通过包含头文件多次声明这个函数,但是我可以直接在需要使用的c文件中直接声明这个函数,实现多个c文件调用同一个函数的情况(一般来说我们的防止重复包含的头文件预处理是针对头文件中的一些定义而不是声明,预处理防的是多次定义同一个东西)
- 然后就是使用LCD1602函数之前要初始化,否则不会有显示