单片机实现电子密码锁实验二.docx
《单片机实现电子密码锁实验二.docx》由会员分享,可在线阅读,更多相关《单片机实现电子密码锁实验二.docx(20页珍藏版)》请在冰豆网上搜索。
单片机实现电子密码锁实验二
<<单片机C语言>>实验二单片机实现电子密码锁
人们在日常生活,工作过程中越来越离不开密码的使用,比如新型小区单元门的电子密码锁,超市的储存柜,智能取款机,公司转帐交易等,这些时候人们接触到的都是一种使用电子密码的装置.电子密码的应用虽然广泛,但是基本原理都大体相同.
一.任务说明
一个简单的电子密码锁就是一个小型的单片机系统.它应该有输入设备,用户可以输入密码并确定或取消;应该有输出设备,用户可以看到显示自己输入正确与否的提示,输出设备还应该包括告警提示.电子密码锁内部的单片机是核心处理设备,它负责获取用户输入的密码,将其和正确的预置密码比较,产生相应的输出.若基于安全角度的考虑,可以让单片机记录下用户输入错误密码的次数,若此次数超过限制,则要采取相应的保护措施,防止他人反复试探密码.
本任务实现一个简单的电子密码锁,用4*4键盘组成0-9数字键以及确认,取消功能键,用4位8段数码管组成显示电路提示信息,其工作过程如下.
●加电后,显示”8888”.
●输入密码时,只逐位显示”F”,以防止泄漏密码.
●输入密码过程中,如果不小心出现输入错误,可按”取消”键清除屏幕,取消此次输入,此时显示”8888”.再次输入需重新输入所有4位密码.
●当密码输入完毕按下”确认”键时,单片机将输入的密码与设定的密码比较,若密码正确,则绿色发光二极管1秒钟(此次表示密码锁打开);若密码不正确,则红色发光二极管亮1秒钟.
二.设计思路分析
经过分析可知,设计具备上述功能的电子密码锁主要需要解决3个问题.
*键盘输入
*数码管显示
*单片机电路以及密码比较与处理的有关程序设计.
1.键盘输入
键盘是一组按键的集合,它是最常用的单片机输入设备.键盘可以分为两类:
独立连接式和矩阵式.
矩阵式键盘,也就是通常所讲的行列式键盘,由航线和列线组成,按键位于行列的交叉点上,行.列分别连接到按键开关的两端,行线通过上拉电阻接到高电平.无按键动作时,行线处于高电平状态;有按键按下时,交点的行线和列线接通,行线电平状态将由与此行线的列线电平决定.列线电平如果低,则行线电平低;列线电平高,则行线电平就高.这一点是识别矩阵键盘按键是否被按下的关键所在.
通过行列键盘扫描的方法可获取键盘输入的键值,从而得知按下的是哪个按键,具体过程如下.
(1)查询是否有键按下.单片机向行扫描口输出全为”0”的扫描码,然后从列检测口检测信号,只要有一列信号不为”1”,则表示有键按下,且不为”1”的列即对应为按下的键所在的列.
(2)查询按下键所在的行,列位置.前面已经取得了按下键的列号,接下来要确定键所在的行,这需要进行逐行扫描.单片机首先使第一行为”0”,其余个行为”1”,接着进行列检测,若为全”1”,表示不在第一行,否则即在第一行;然后使第二行为”0”,其余各行为”1”,再进行列检测,若为全”1”,表示不在第二行,否则即在第二行;这样逐行检测,直到找到按下键所在的行.当各行都扫描以后仍没有找到,则放弃扫描,认为是键的误动作.
(3)对得到的行号和列号进行译码,得到键值.对于4*4的行列式键盘,因为按键的位置由行号和列号唯一确定,且行列各四位,所以用一个字节(8位)来对键值编码是很合适的.本任务中,将字节的高四位(D7,D6,D5,D4)表示列号(4,3,2,1),低4位(D3,D2,D1,D0)表示行号(4,3,2,1),比如11H(00010001)表示第一行第一列,21H(00100001)表示第一行第二列,24H(00100100)表示第三行第二列.
在扫描键过程中,应注意以下问题.
消除键抖动等
对应上面的键盘及键盘的键值编码方法,各按键及其编码的对应关系如下表所示:
按键行号列号键值编码
01111H(00010001)
11221H(00100001)
21341H(01000001)
31481H(10000001)
42112H(00010010)
52222H(00100010)
62342H(01000010)
72482H(10000010)
83114H(00010100)
93224H(00100100)
确认3344H(01000100)
取消3484H(10000100)
2数码管显示
八段数码管由8个发光二极管LED组成,每一个LED称为一字段,共8段:
a,b,c,d,e,f,g,dp,其中dp为小数点,如上图所示:
八段数码管可以显示包括小数点的0-9数字和部分的英文字母.为了获得不同的字型,数码管各段锁加的电平也不同,编码也不一样.字型字段和编码的关系如下表所示(以共阴极数码管为例)
字型
D7
D6
D5
D4
D3
D2
D1
D0
编码
dp
g
f
e
d
c
b
a
0
0
0
1
1
1
1
1
1
3F
1
0
0
0
0
0
1
1
0
06
2
0
1
0
1
1
0
1
1
5B
3
0
1
0
0
1
1
1
1
4F
4
0
1
1
0
0
1
1
0
66
5
0
1
1
0
1
1
0
1
6D
6
0
1
1
1
1
1
0
1
7D
7
0
0
0
0
0
1
1
1
07
8
0
1
1
1
1
1
1
1
7F
9
0
1
1
0
1
1
1
1
6F
A
0
1
1
1
0
1
1
1
77
B
0
1
1
1
1
1
0
0
7C
C
0
0
1
1
1
0
0
1
39
D
0
1
0
1
1
1
1
0
5E
E
0
1
1
1
1
0
0
1
79
F
0
1
1
1
0
0
0
1
71
单片机驱动LED数码管有静态显示和动态扫描显示两种方法,其中后者较为常用.
动态扫描方法是用其接口电路把所有显示器的8个笔画字段(a-g和dp)同名端连接在一起,而每一个显示器的公共极COM各自独立的接受I/O线控制.CPU向字段输出端口输出字型码时,所有显示器接收到相同的字型码,但究竟使用哪个显示器,则取决与COM端,而这一端是由I/O控制的,由单片机决定何时显示哪一位.动态扫描用分时的方法轮流控制各个显示器的COM端,使各个显示器轮流点亮.
三.硬件电路设计
本任务的硬件电路是51单片机系统的典型电路,由单片机,键盘输入,数码管及指示灯输出三部分构成.
1结构框图
2主要器件
本任务使用的主要器件如下:
(1)单片机,它接收键盘的输入并作出判断,控制4位8段数码管和LED指示灯的显示.
(2)4*4行列式键盘.用户通过键盘输入4位密码及确认,取消功能键.
(3)8段数码管.共4位数码管,对应于4位密码.
(4)LED指示灯,红绿两个LED指示灯,红灯表示输入密码错误,绿灯表示输入密码正确,锁打开.
(5)CMOS六反相驱动器CD4069UB.CD4069UB对单片机的P2.0-P2.5进行反相操作以提供正确的数码管位选择信号,它可以提供足够的驱动电流.
3电路原理图及说明
系统的电路图分为3部分:
一是单片机及键盘电路原理图,如图所示:
二是位驱动及指示灯电路原理图,如图所示:
三是4位8段数码管显示电路原理图,如图所示:
说明:
U1为单片机芯片,它是整个电路的核心器件,联系着输入和输出.
P1口用于键盘操作,P1.0-P1.3与行线相连,R2-R5为行线的上拉电阻,P1.4-P1.7与列线相连.
P0口用作8段数码管的字段选择信号,控制数码管的字段LED发光,RP1为220欧的上拉排组.
P2口的P2.0-P2.3用于产生4位数码管的位选择信号,控制应该显示的8段数码管发光,位选择信号C1-C4需由P2.0-P2.3经由6反相器CD4096UB反相驱动.
P3.0P3.1作普通I/O口使用,前者控制绿色发光二极管,指示密码输入正确状态;
后者控制红色发光二极管,指示密码输入错误状态.
四.软件设计
软件可分为两部分.
1键盘输入.通过行列键盘扫描程序获取所按键的行,列号,并根据表1得到其键值编码.注意:
在键盘扫描时需进行消抖处理.
2数码管显示和指示灯输出.根据获取的键值编码,选择相应的功能,驱动数码管和指示灯显示.
五.程序流程
六.程序详解
#ifndef_PWLOCK_H//防止PWLock.h被重复引用
#define_PWLOCK_H
#include
#include
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
uchardigbit;//字位
ucharwordbuf[6];//字型码缓冲区
uchart1count;//定时器1由50ms累积到1s所用的计数器
ucharcount;//密码位计数
ucharpw[6];//初始密码存储区
ucharpwbuf[6];//输入密码存储区
bitenterflag;//确认键按下与否标志
bitpwflag;//密码正确与否标志
bitshowflag;//数码管显示与否标志
sbitgreen=P3^0;
sbitred=P3^1;
voiddisplay(void);//显示函数
#endif
#include"PWLock.h"
/*键消抖延时函数*/
voiddelay(void)
{
uchari;
for(i=300;i>0;i--);
}
/*键扫描函数*/
ucharkeyscan(void)
{
ucharscancode,tmpcode;
P1=0xf0;//发全0行扫描码
if((P1&0xf0)!
=0xf0)//若有键按下
{
delay();//延时去抖动
if((P1&0xf0)!
=0xf0)//延时后再判断一次,去除抖动影响
{
scancode=0xfe;
while((scancode&0x10)!
=0)//逐行扫描
{
P1=scancode;//输出行扫描码
if((P1&0xf0)!
=0xf0)//本行有键按下
{
tmpcode=(P1&0xf0)|0x0f;
/*返回特征字节码,为1的位即对应于行和列*/
return((~scancode)+(~tmpcode));
}
elsescancode=(scancode<<1)|0x01;//行扫描码左移一位
}
}
}
return(0);//无键按下,返回值为0
}
/*定时器0中断服务子程序,2ms定时动态扫描显示*/
voidtime0_int(void)interrupt1
{
/*重置2ms定时*/
TH0=65536-2000/256;
TL0=65536-2000%256;
if(showflag==1)
display();//调用显示函数
}
/*定时器1中断服务子程序,50ms*/
voidtime1_int(void)interrupt3
{
uchark;
/*重置50ms定时*/
TH1=65536-50000/256;
TL1=65536-50000%256;
if(t1count<20)
{
t1count++;
}
else//计时到1s
{
TR1=0;//关闭计数器1
t1count=0;
green=1;//绿灯不亮
red=1;//红灯不亮
showflag=1;//打开数码管显示
digbit=0x01;//从数码管第1位开始动态显示
for(k=0;k<4;k++)//显示8888
wordbuf[k]=8;
}
}
/*根据共阴极字型编码表获取0~9,A~B字型代码*/
uchargetcode(uchari)
{
ucharp;
switch(i)
{
case0:
p=0x3f;break;/*0*/
case1:
p=0x06;break;/*1*/
case2:
p=0x5B;break;/*2*/
case3:
p=0x4F;break;/*3*/
case4:
p=0x66;break;/*4*/
case5:
p=0x6D;break;/*5*/
case6:
p=0x7D;break;/*6*/
case7:
p=0x07;break;/*7*/
case8:
p=0x7F;break;/*8*/
case9:
p=0x67;break;/*9*/
case10:
p=0x77;break;/*A*/
case11:
p=0x7C;break;/*B*/
case12:
p=0x39;break;/*C*/
case13:
p=0x5E;break;/*D*/
case14:
p=0x79;break;/*E*/
case15:
p=0x71;break;/*F*/
default:
break;
}
return(p);
}
/*显示函数*/
voiddisplay(void)
{
uchari;
switch(digbit)
{
case1:
i=0;break;
case2:
i=1;break;
case4:
i=2;break;
case8:
i=3;break;
default:
break;
}
P2=0x0;//关闭显示
P0=getcode(wordbuf[i]);//送字型码
P2=digbit;//送字位码
if(digbit<0x08)//共4位
digbit=digbit*2;//左移一位
else
digbit=0x01;
}
/*密码比较函数*/
bitpwcmp(void)
{
bitflag;
uchari;
for(i=0;i<4;i++)
{
if(pw[i]==pwbuf[i])
flag=1;
else
{
flag=0;
i=4;
}
}
return(flag);
}
/*主程序*/
voidmain()
{
ucharj,key;
P2=0x0;//关闭数码管显示
TMOD=0x11;//T0,T1工作方式1
/*2ms定时设置*/
TH0=-2000/256;
TL0=-2000%256;
/*50ms定时设置*/
TH1=-50000/256;
TL1=-50000%256;
/*启动计数器0,关闭计数器1*/
TR0=1;
ET0=1;
TR1=0;
ET1=1;
EA=1;
count=0;//初始没有输入密码,计数器设为0
enterflag=0;//没有按下确认键
pwflag=0;//密码标志先置为0
green=1;//绿灯不亮
red=1;//红灯不亮
/*假设内定密码为9376*/
pw[0]=9;
pw[1]=3;
pw[2]=7;
pw[3]=6;
digbit=0x01;//从第一位数码管开始动态扫描
/*刚加电时,显示8888*/
for(j=0;j<4;j++)
wordbuf[j]=8;
showflag=1;//打开数码管显示
while
(1)
{
key=keyscan();//调用键盘扫描函数
switch(key)
{
case0x11:
//1行1列,数字0
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F”
pwbuf[count]=0;
count++;
}
break;
case0x21:
//1行2列,数字1
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F"
pwbuf[count]=1;
count++;
}
break;
case0x41:
//1行3列,数字2
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F"
pwbuf[count]=2;
count++;
}
break;
case0x81:
//1行4列,数字3
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F"
pwbuf[count]=3;
count++;
}
break;
case0x12:
//2行1列,数字4
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F"
pwbuf[count]=4;
count++;
}
break;
case0x22:
//2行2列,数字5
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F"
pwbuf[count]=5;
count++;
}
break;
case0x42:
//2行3列,数字6
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F"
pwbuf[count]=6;
count++;
}
break;
case0x82:
//2行4列,数字7
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F"
pwbuf[count]=7;
count++;
}
break;
case0x14:
//3行1列,数字8
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F"
pwbuf[count]=8;
count++;
}
break;
case0x24:
//3行2列,数字9
if(count<4)
{
wordbuf[count]=0x0f;//对应密码位上显示“F"
pwbuf[count]=9;
count++;
}
break;
case0x44:
//3行3列,确认键
enterflag=1;//确认键按下
if(count==4)//只有输入4个密码后按确认键才作密码比较
pwflag=pwcmp();
else
pwflag=0;//否则直接pmflag赋0
break;
case0x84:
//3行4列,取消键
count=0;//密码计数清零
for(j=0;j<4;j++)
{
wordbuf[j]=8;//数码管显示8888
pwbuf[j]=0x0f;//用FFFF清除已经输入的密码
}
break;
default:
break;
}
if(enterflag==1)//如果按下确认键
{
enterflag=0;//标志位置回0
count=0;//密码位计数器清零
for(j=0;j<4;j++)
pwbuf[j]=0x0f;//用FFFF清除已经输入的密码
showflag=0;//关闭数码管显示
TR1=1;//计数器1开始计数
t1count=0;//定时器1由50ms累积到1s所用的计数器
if(pwflag==1)
green=0;