(6)普中A2 51单片机矩阵键盘和密码锁 - 详解
- 在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式
- 采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态

例如现在16个,每个按钮都接入一个单独的IO口,就需要16个IO口,如果通过行列扫描,只需要4+4个,看似差距不大,但是将数量扩大一点,例如100x100个,每个都需要一个单独的IO口,就需要10000个,而采用行列扫描,只需要100+100,我们日常使用的显示器也是使用行列扫描的,这样就可以大大的减少IO口的数量。
- 数码管扫描 (输出扫描)
原理:显示第1位→显示第2位→显示第3位-然后快速循环
这个过程,最终实现所有数码管同时显示的效果 - 矩阵键盘扫描 (输入扫描)
原理:读取第1行(列)→读取第2行(列)→读取第3行(列)
然后快速循环这个过程,最终实现所有按键同时检测的效果 - 以上两种扫描方式的共性:节省I/O口
然后下面是工程文件,总共五个。mk.h,mk.c,LCD1602.c,LCD1602.h,main.c。
- mk.c
#include <REGX52.H>
#include <intrins.h>
void Delay(unsigned char x) //@11.0592MHz
{
while(x--)
{
unsigned char data i, j;
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
unsigned char mk()
{
unsigned char Kn=0;
P1=0xFF;
P1_3=0;
if(P1_7==0)
{
Delay(20);
while(P1_7==0);
Delay(20);
Kn=1;
}
if(P1_6==0)
{
Delay(20);
while(P1_6==0);
Delay(20);
Kn=5;
}
if(P1_5==0)
{
Delay(20);
while(P1_5==0);
Delay(20);
Kn=9;
}
if(P1_4==0)
{
Delay(20);
while(P1_4==0);
Delay(20);
Kn=13;
}
P1=0xFF;
P1_2=0;
if(P1_7==0)
{
Delay(20);
while(P1_7==0);
Delay(20);
Kn=2;
}
if(P1_6==0)
{
Delay(20);
while(P1_6==0);
Delay(20);
Kn=6;
}
if(P1_5==0)
{
Delay(20);
while(P1_5==0);
Delay(20);
Kn=10;
}
if(P1_4==0)
{
Delay(20);
while(P1_4==0);
Delay(20);
Kn=14;
}
P1=0xFF;
P1_1=0;
if(P1_7==0)
{
Delay(20);
while(P1_7==0);
Delay(20);
Kn=3;
}
if(P1_6==0)
{
Delay(20);
while(P1_6==0);
Delay(20);
Kn=7;
}
if(P1_5==0)
{
Delay(20);
while(P1_5==0);
Delay(20);
Kn=11;
}
if(P1_4==0)
{
Delay(20);
while(P1_4==0);
Delay(20);
Kn=15;
}
P1=0xFF;
P1_0=0;
if(P1_7==0)
{
Delay(20);
while(P1_7==0);
Delay(20);
Kn=4;
}
if(P1_6==0)
{
Delay(20);
while(P1_6==0);
Delay(20);
Kn=8;
}
if(P1_5==0)
{
Delay(20);
while(P1_5==0);
Delay(20);
Kn=12;
}
if(P1_4==0)
{
Delay(20);
while(P1_4==0);
Delay(20);
Kn=16;
}
return Kn;
}
- mk.h
#ifndef __MK_H__
#define __MK_H__
unsigned char mk();
#endif
- main.c
#include <REGX52.H>
#include <LCD1602.h>
#include <intrins.h>
#include "mk.h"
unsigned char kn;
int count=0;
unsigned long ps=0;
int temp1=0;
int temp2=0;
int main()
{
LCD_Init();
LCD_ShowString(1,1,"hello");
while(1)
{
kn=mk();
if(kn)
{
if(kn<=10)
{
if(count<6)
{
ps=ps*10+(kn%10);
}
count++;
temp1=ps%1000;
temp2=ps/1000;
LCD_ShowNum(2,4,temp1,3);
LCD_ShowNum(2,1,temp2,3);
}
if(kn==11)
{
if(ps==123456)
{
LCD_ShowString(2,10,"YES");
}
else
{
LCD_ShowString(2,10,"ERR");
}
count=0;
ps=0;
LCD_ShowNum(2,1,0,6);
}
if(kn==12)
{
count=0;
ps=0;
LCD_ShowNum(2,1,0,6);
}
}
}
}
LCD1602的.c文件和.h文件可以查看我前面写的LCD1602调试的文章。
mk的c文件和h文件写的是矩阵键盘扫描的逻辑,先选中一列,然后判断每一行,看是否被选中,然后对每一列都进行这样的判断,就可以扫描全部16个按键,同时也要用到我们前面学的独立按键消抖的知识,加入一定的延时。
先说一下主函数的功能,矩阵按键1-9对应数字1-9,按键10对应0,然后按键11是确认,按键12是取消重新输入,其他按键没有功能。
主函数通过ps存储密码,每次输入一个数字,就对原本的ps乘10,再加上这个数,就做到了移位的效果。同时设定一个count进行计数,密码设定为6位,到6位在确认和取消之前,再进行输入将不起作用。每次当我们确认或者取消的时候,需要将密码给重置,也就是将ps设置为0,count计数器也设置为0.然后当我们按下确认之后,就需要判断密码和设定的密码是否相同,根据结果在屏幕上显示YES或者ERR。
原本的教程是4位密码,我进行了一点改进,使用了long类型,可以存储更长的数据,然后那个LCD1602显示数字的函数,是使用的int型,传入的long类型数据会被自动类型转换为int型,也就会导致数据丢失,所以我选择使用temp1和temp2存储ps的前3位和后3位,然后进行显示。就没有问题了。
矩阵键盘密码锁

浙公网安备 33010602011771号