1 课程设计题目要求
用户可以设计 4~6 位密码;采用矩阵键盘进行输入; 用红、绿 2 个 LED 小灯模拟锁的状态:绿灯灭,红灯亮(锁未开);绿灯亮, 红灯灭(锁开)。
2 设计方案
2.1 设计任务分析
本设计以单片机为核心,完成密码的设置、存贮、识别、修改等功能。
简易密码锁是由4部分组成,单片机控制模块,矩阵键盘模块,显示模块,电源模块组成。其中矩阵键盘用于输入数字密码和进行各功能的实现。
2.2 设计方案构想
方案一:以数码管作为显示电路用以显示输入的密码。这个方案的优点是数码管便宜,编写代码简单。缺点是只用数码管,无法显示详细的语段。故并未编写更多的按键功能。
设计流程图
开始接上电源,程序进行初始化设置,系统进行键盘扫描,然后进行设置密码,确认后,点击输入密码,确认后进行密码对比,如密码正确,则开锁成功。
方案二:以LCD液晶显示屏显示输入密码等。这个方案的优点是用LCD1602液晶显示相比于数码管显示清晰明了。缺点是代码繁杂,LCD液晶显示屏较数码管昂贵。
开始运行程序,可以看到LCD1602显示的是“input password”的字符,提示输入密码,密码错误,则显示“error input again”提示再次输入密码。然后在输对密码之后,显示的是“welcome”,表示锁已经打开,另外,在输对密码的同时,可以进行修改密码,显示的是“change password”,代表可以进行修改密码,修改密码之后将记住新的密码。
3 电路设计与仿真
3.1 单片机控制模块
本设计中采用AT89C51单片机作为整个系统的核心,以其优势——控制简单、方便、快捷,用其进行密码锁的控制,以实现其既定的性能指标。晶振电路为单片机合格的时钟信号流,给整个电路的时序提供一个基本时钟。
3.2 矩阵键盘模块
方案一开发为使用按键中断,只进行了矩阵按键的使用,在第一次按键与第二次按键的过程间,均进行了按键的等待释放,以及等待按键按下的判断,提高程序的正确性。该矩阵键盘用了8个IO口分别为P2.0-P2.7。
各行按键的功能为:
0 1 2 3
4 5 6 7
8 9
登出 设置密码 输入密码 登入
方案二按键工作处于两种状态:按下与释放。一般按下为接通,释放为断开,这两种状态要被CPU识别,通常将两种状态转换为与之对应的低电平或高电平。CPU通过按键信号电平的高低来判断按键的状态。
该方案没有用字母,仅仅是用0~9十个数字以及确定和重置十二个键。所以矩阵键盘也只用了7个IO口分别为P1.0-P1.6。
各行按键的功能为:
1 4 7 设置密码
2 5 8 0
3 6 9 确定
3.3 显示模块
方案一采用六位(实际只用上四位)共阳数码管动态扫描显示方法,只需7个I/O口就可以同时驱动多个数码管显示,价格便宜,驱动程序容易理解和编程。P0.0-P0.7用作数码管段码端,P1.0-P1.3用作数码管位码端。
表示关锁的红色LED灯接P3.6口。表示开锁的绿色LED灯接P3.7口。
方案二采用专门显示字母、数字、符号等点阵式LCD。P0.0-P0.7用作LCD1602的数据输入,P2.5,P2.6,P2.7用作LCD的控制端。
表示关锁的红色LED灯接P2.2口。表示开锁的绿色LED灯接P2.3口。
4 实物制作与调试
4.1 4.1 仿真调试
单片机应用系统的仿真调试和软件调试是分不开的,但通常是先排除系统中明显的仿真故障后才和软件结合起来调试。在进行仿真调试时先仔细检查线路核对元器件的型号、规格是否正确。
4.2 硬件调试
单片机应用系统的硬件调试和软件调试是分不开的,但通常是先排除系统中明显的硬件故障后才和软件结合起来调试。在进行硬件调试时先进行静态调试,用万用表等工具在样机加电前根据原理图和装配图仔细检查线路核对元器件的型号、规格哈安装是否正确。然后加电检查各点电位是否正常。接下来再借助仿真器进行联机调试,分别测试扩展的RAM、I/O口、I/O设备、程序存储器以及晶振和复位电路并改正其中的错误。
第一步:在没通电之前先用万用表检查线路的正确性并核对元器件的型号、规格是否符合要求。特别注意电源的正负极以及电源之间是否有短路并检查地址总线、数据总线、控制总线是否存在相互间的短路或其它信号线的短路。由于本系统的开发是基于曾经用过的单片机,所以此步骤不会发生故障。
第二步:通电后检查单片机I/O的电位,测量各点电位是否正常。尤其是应注意单片机输出口的各点电位。若有高压将有可能损坏外部仿真电路,同样如果电压过低就没有能力驱动负载。
第三步:将单片机信号输出接口与外部仿真电路接口连接起来,为软件调试做好准备。
5 课程设计总结
总体来看,完成了题目所要求的基本功能,但仍有不足,如无法实现用户可自行设4-6位密码,仅能固定位数。这次课设,尽管时间紧迫,无法完善许多功能,但仍使我从中学到许多知识,不管是专业基础知识还是动手制作能力,都得到了很大的提高,既开拓了思维也积累了经验,更重要的是使我看到自己的不足和今后更需努力。
参考文献
[1]张齐,杜群贵.《单片机应用系统设计技术》[M].电子工业出版社,2004.
[2]杨素行.《模拟电子技术基础》[M].高等教育出版社,2006.
[3]陈应华,刘志芳.《电路与电工技术》[M].中国人民大学出版社,2014.
[4]许维菳,郑荣焕.《Proteus电子电路设计及仿真》[M].电子工业出版社,2014.
[5]王会良,王东锋,董冠强.《单片机C语言应用100例》[M].中国工信出版集团,2017.
[6]朱清慧,张凤蕊,翟天嵩,王志奎.《Proteus教程——电子线路设计、制版与仿真》[M].清华大学出版社,2008.
[7]王秀艳,姜航,谷树忠.《Altium Designer教程——原理图、PCB设计》[M].中国工信出版集团,2019.
附 录
1.电路图
方案二
2.仿真图
方案一
方案二
3. 实物图
4.元器件清单
AT89C51单片机1个,四脚按键13个,红色发光二极管1个,绿色发光二极管1个,发光二极管1个,12MHz晶振1个,45uF电容4个,10k电阻11个,电源座子1个
5.程序代码
方案一
#include<reg51.h>
sbit LEDR=P3^6;
sbit LED1=P3^7;
int count=-1;
int count1=0;
int counter;
int counter1=0;
int temp=99,signal=0;
int key_word[4]={99,99,99,99};
int get_word[4]={0,0,0,0};
char key_buf[]={0xee,0xde,0xbe,0x7e,
0xed,0xdd,0xbd,0x7d,
0xeb,0xdb,0xbb,0x7b,
0xe7,0xd7,0xb7,0x77};
char led[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//0-9
void set_key();
void show1(int);
void input_key();
void show2(int);
void show3();
void show4();
int get_key();
void delay(int x)
{
int j=0;
for(;x>0;x--)
for(j=0;j<125;j++);
}
void set_key()
{
int i;
for(i=0;i<4;i++)
{
while(get_key()==-1)
{
if(count!=0&&count!=-1)
{
show1(count);
}
}
if(signal==1)
{
key_word[i]=get_key();
count++;
show1(count);
signal=0;
temp=99;
}
while(temp==get_key())
{
show1(count);
}
}
}
void input_key()
{
int i;
for(i=0;i<4;i++)
{
while(get_key()==-1)
{
if(count!=0&&count!=-1)
{
show2(count);
}
}
if(signal==1)
{
get_word[i]=get_key();
count++;
show2(count);
signal=0;
}
while(temp==get_key())
{
show2(count);
}
}
}
void show2(int count)//input
{
if(count==0)
{
P1=0x0e;
P0=led[get_word[0]];
}
if(count==1)
{
P1=0x0e;
P0=led[get_word[0]];
delay(10);
P1=0x0d;
P0=led[get_word[1]];
delay(10);
}
if(count==2)
{
P1=0x0e;
P0=led[get_word[0]];
delay(10);
P1=0x0d;
P0=led[get_word[1]];
delay(10);
P1=0x0b;
P0=led[get_word[2]];
delay(10);
}
if(count==3)
{
P1=0x0e;
P0=led[get_word[0]];
delay(10);
P1=0x0d;
P0=led[get_word[1]];
delay(10);
P1=0x0b;
P0=led[get_word[2]];
delay(10);
P1=0x07;
P0=led[get_word[3]];
delay(10);
P0=0;
//count=-1;
signal=0;
}
}
void show1(int count)//set
{
int i;
if(count==0)
{
P1=0x0e;
i=key_word[0];
P0=led[i];
}
if(count==1)
{
P1=0x0e;
P0=led[key_word[0]];
delay(10);
P1=0x0d;
P0=led[key_word[1]];
delay(10);
}
if(count==2)
{
P1=0x0e;
P0=led[key_word[0]];
delay(10);
P1=0x0d;
P0=led[key_word[1]];
delay(10);
P1=0x0b;
P0=led[key_word[2]];
delay(10);
}
if(count==3)
{
P1=0x0e;
P0=led[key_word[0]];
delay(10);
P1=0x0d;
P0=led[key_word[1]];
delay(10);
P1=0x0b;
P0=led[key_word[2]];
delay(10);
P1=0x07;
P0=led[key_word[3]];
delay(10);
P0=0;
count=-1;
signal=0;
}
}
int get_key()
{
char key_scan[]={0xef,0xdf,0xbf,0x7f};
int i=0;
int j=0;
for(i=0;i<4;i++)
{
P2=key_scan[i];
if((P2&0x0f)!=0x0f)
{
for(j=0;j<16;j++)
{
if(key_buf[j]==P2)
{
if(temp!=key_buf[j])
{
signal=1;
temp=j;
return j;
}
else signal=0;
}
}
}
}
return -1;
}
int compare()
{
int i;
for(i=0;i<4;i++)
{
if(get_word[i]!=key_word[i])
return -1;
}
return 1;
}
void show3()//err
{
P1=0x0e;
P0=0x79;
delay(10);
P1=0x0d;
P0=0x77;
delay(10);
P1=0x0b;
delay(10);
LEDR=1;
LED1=0;
}
void show4()//on
{
P1=0x0e;
P0=0x5c;
delay(10);
P1=0x0d;
P0=0x54;
delay(10);
}
void main()
{
int op;
LED1=0;
LEDR=0;
while(1)
{
op=get_key();
switch(op)
{
case 13:
while(temp==get_key());
count=-1;
signal=1;
set_key();
break;
case 14:
while(temp==get_key());
count=-1;
signal=1;
input_key();
while(get_key()!=15)
{
show2(count);
}
if(compare()==-1)
{
count1++;
while(get_key()!=14&&count1!=3)
{
show3();
}
P0=0;
if(count1==3)
{
TMOD=0x01;
TH0=0x9E;//25ms
TL0=0x58;
EA=1;
ET0=1;
TR0=1;
while(counter1<60);
TR0=0;
}
}
else
{
LED1=1;
LEDR=0;
while(get_key()!=12)//on
{
show4();
}
LED1=0;
LEDR=0;
P0=0;
}
break;
default:break;
}
}
}
方案二
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit en=P2^7;
sbit rw=P2^5;
sbit rs=P2^6;
sbit kai=P2^2;
sbit guan=P2^3;
sbit key0=P3^7;
uchar table[10];
uchar keycmp[4];
uchar keyword[4]={1,1,1,1};
uchar num=0,flg=0,key=0,ala=0,in=0;
void close()//关
{
kai=0;
guan=1;
}
void kaisuo()//开
{
kai=1;
guan=0;
}
void delay(uint x)
{
uint i,j;
for(i=x;i>0;i--)
for(j=100;j>0;j--);
}
void lcd_wcom(uchar com)//1602写命令函数
{
rs=0;//选择指令寄存器
rw=0;//选择写
P0=com;//把命令字送入P0
delay(5);
en=1;//使能线电平变化,命令送入1602的8位数据口
en=0;
}
void lcd_wdat(uchar dat)//1602写数据函数
{
rs=1;
rw=0;
P0=dat;//把要显示的数据送入P0
delay(5);
en=1;
en=0;
}
void lcd_init()//1602初始化函数
{
lcd_wcom(0x38);//8位数据,双列,5*7字形
lcd_wcom(0x0c);//开启显示屏,关光标,光标不闪烁
lcd_wcom(0x06);//显示地址递增,即写一个数据后,显示位置右移一位
lcd_wcom(0x01);//清屏
}
void display()
{
uchar i,j;
j=num+0x46;
lcd_wcom(0x80+j);
i=keycmp[num];
i=i+0x30;
table[0]=i;
lcd_wdat(table[0]);
}
void right()
{
uchar n=0;
uchar code table1[]="welcome";
lcd_wcom(0x01);//清屏
lcd_wcom(0x84);//显示地址
kaisuo();
for(n=0;n<7;n++)
{
lcd_wdat(table1[n]);
delay(200);
}
num=0;
flg=2;
in=1;
}
void indisplay()
{
uchar n=0;
uchar code table5[]="input password";
lcd_wcom(0x01);
lcd_wcom(0x80);
for(n=0;n<14;n++)
{
lcd_wdat(table5[n]);
delay(200);
}
}
void setdisplay()
{
uchar n=0;
uchar code table2[]="change password";
lcd_wcom(0x01);
lcd_wcom(0x80);
for(n=0;n<15;n++)
{
lcd_wdat(table2[n]);
delay(200);
}
}
void error()
{
uchar n,m;
uchar code table3[]="error";
uchar code table4[]="input again";
lcd_wcom(0x01);
lcd_wcom(0x85);
close();
for(n=0;n<6;n++)
{
lcd_wdat(table3[n]);
delay(100);
}
lcd_wcom(0x80+0x42);
for(m=0;m<11;m++)
{
lcd_wdat(table4[m]);
delay(100);
}
}
void set()
{
if(in==1)
{
num=0;
flg=1;
setdisplay();
}
else error();
}
void okdisplay()
{
uchar n;
uchar code table6[]="ok";
lcd_wcom(0x01);
lcd_wcom(0x87);
for(n=0;n<2;n++)
{
lcd_wdat(table6[n]);
delay(200);
}
}
void ok()
{
uchar i=0;
if(flg==0)
{
for(i=0;i<4;i++)
if(keyword[i]!=keycmp[i])
{
error();
return;
}
if(num==4)
{
right();
return;
}
}
if(flg==1)
{
if(num==4)
{
num=0;
for(i=0;i<4;i++)
keyword[i]=keycmp[i];
okdisplay();
flg=2;
return;
}
else error();
return;
}
if(flg==2)
{uchar aa,bb;
while(1)
{
P1=0xfb;//检测第3行
aa=P1;
if(aa!=0xfb)
{
delay(5);
bb=P1;
if(bb==0xbb)
{break;}
}
}
indisplay();
num=0;
flg=0;
return;
}
}
void keyscan()
{
uchar temp1,temp2,temp3;
P1=0xfe;//检测第1行
temp1=P1;
if(temp1!=0xfe)
{
delay(5);
temp2=P1;
if(temp1==temp2)
{
switch(temp2)
{
case 0xf6:
if(num<4)
{
key=1;
keycmp[num]=key;
display();
num++;
}
else error();
break;
case 0xee:
if(num<4)
{
key=4;
keycmp[num]=key;
display();
num++;
}
else error();
break;
case 0xde:
if(num<4)
{
key=7;
keycmp[num]=key;
display();
num++;
}
else error();
break;
case 0xbe:
set();
break;
}
}
}
while(temp1!=0xfe)temp1=P1;//2
P1=0xfd;
temp1=P1;
if(temp1!=0xfd)
{
delay(5);
temp2=P1;
if(temp1==temp2)
{
switch(temp2)
{
case 0xf5:
if(num<4)
{
key=2;
keycmp[num]=key;
display();
num++;
}
else error();
break;
case 0xed:
if(num<4)
{
key=5;
keycmp[num]=key;
display();
num++;
}
else error();
break;
case 0xdd:
if(num<4)
{
key=8;
keycmp[num]=key;
display();
num++;
}
else error();
break;
case 0xbd:
if(num<4)
{
key=0;
keycmp[num]=key;
display();
num++;
}
else error();
break;
}
}
}
while(temp1!=0xfd)temp1=P1;//3
P1=0xfb;
temp1=P1;
if(temp1!=0xfb)
{
delay(5);
temp2=P1;
if(temp1==temp2)
{
switch(temp2)
{
case 0xf3:
if(num<4)
{
key=3;
keycmp[num]=key;
display();
num++;
}
else error();
break;
case 0xeb:
if(num<4)
{
key=6;
keycmp[num]=key;
display();
num++;
}
else error();
break;
case 0xdb:
if(num<4)
{
key=9;
keycmp[num]=key;
display();
num++;
}
else error();
break;
case 0xbb:
if(flg==0)ok();
if(flg==1)ok();
if(flg==2)ok();
else error();
break;
}
}
}
}
void main()
{
kai=0;
guan=0;
lcd_init();
indisplay();
while(1)
{
keyscan();
}
}