简介
大家好,这篇文章的内容是关于如何用51单片机来制作一个电子密码锁的教程,通过这篇教程可以让刚入门的朋友了解矩阵键盘、LCD1602的使用方法,以及密码输入和修改的程序介绍,我会对每个部分进行详细的介绍。
首先我们来看一下这个密码锁要实现哪些功能:
可通过矩阵键盘进行密码的输入和修改。
可通过LCD1602进行界面的显示。
在了解了我们需要实现的功能后我们就可一开始进行软硬件的设计了。本次密码锁的硬件部分我使用Proteus来进行仿真。
硬件设计
首先我们进行硬件的设计,密码锁的硬件部分还是很简单的,首先我们需要一个51单片机的最小系统,在Proteus中芯片并不需要外接晶振,直接放上芯片就可以使用,我选择AT89C52单片机,并给P0口外接一排上拉电阻来提升驱动能力,
接下来是界面显示部分,之前说过显示部分使用的是LCD1602,LCD的电路如下图,
首先我来简单介绍一下LCD1602的引脚功能:
VSS:接地
VDD:接电源
V0:对比度调整端,使用时可接电位器接地进行对比度调节
RS:寄存器选择,高电平选择数据寄存器,低电平选择指令寄存器
RW:读写信号线,高电平读,低电平写
E:使能端,下降沿写操作,高电平读操作
DB0:数据总线最低位
DB1:数据总线1位
DB2:数据总线2位
DB3:数据总线3位
DB4:数据总线4位
DB5:数据总线5位
DB6:数据总线6位
DB7:数据总线7位
A:背光电源正极
K:背光电源负极
我们可以看到LCD1602一共有上述16个引脚,我来根据图中的接法来介绍一下各个引脚的用法。
VDD和A分别用于给LCD和背光板供电,VSS和K为负极接地,仿真里面我们不需要接A、K引脚。
V0脚就是图中的VEE,这个脚使用来调节LCD的字符对比度,直接接地的时候对比度最高,不过容易出现鬼影,在实际使用的时候我们可以将这个脚通过一个10K的电位器接地来进行对比度的调节,在仿真里我就直接接地了。
RS脚是寄存器选择脚,这个脚我接到单片机的P3.5脚上,我们通过改变这个脚的高低电平可以选择给LCD发送数据还是发送指令。
RW脚是用来设置对LCD的读写操作的,因为在这里我们不需要对LCD进行读取操作,所以我就直接将这个脚接地了,也可以通过IO口来对RW进行设置。
E脚是LCD的使能端,仿真中接的单片机的P3.4脚。
最后的D0~D7脚就是LCD的数据脚,我们将这8个脚接到单片机接了上拉电阻的P0脚,这样就可以给LCD发送指令或数据了。
然后我们需要一个键盘进行密码的输入和修改,在Proteus里我们可以直接搜索KEYPAD来添加矩阵键盘,在这里我们使用一个3*4的键盘就够了,引脚与单片机的连接如下,
也可以使用按键自己连接一个矩阵键盘有助于对程序的理解。
软件设计
在介绍完硬件部分的设计后,我们就可以开始编写程序了,首先讲一下矩阵键盘的程序,
int keyboard() //键盘扫描 { P2 = 0xf7; k = P2; k = k & 0xf0; if(k == 0xf0) { kf = 0; } if(k != 0xf0) { delay(4); k = P2; k = k & 0xf0; if(k != 0xf0) { switch(k) { case 0xe0: key = 88;mod = 1;kf = 1; break; case 0xd0: key = 0;kf = 1; break; case 0xb0: key = 88;kf = 1; break; case 0x70: key = 88;kf = 1; break; } } } P2 = 0xfb; k = P2; k = k & 0xf0; if(k != 0xf0) { delay(4); k = P2; k = k & 0xf0; if(k != 0xf0) { switch(k) { case 0xe0: key = 7;kf = 1; break; case 0xd0: key = 8;kf = 1; break; case 0xb0: key = 9;kf = 1; break; case 0x70: key = 88;kf = 1; break; } } } P2 = 0xfd; k = P2; k = k & 0xf0; if(k != 0xf0) { delay(4); k = P2; k = k & 0xf0; if(k != 0xf0) { switch(k) { case 0xe0: key = 4;kf = 1; break; case 0xd0: key = 5;kf = 1; break; case 0xb0: key = 6;kf = 1; break; case 0x70: key = 88;kf = 1; break; } } } P2 = 0xfe; k = P2; k = k & 0xf0; if(k != 0xf0) { delay(4); k = P2; k = k & 0xf0; if(k != 0xf0) { switch(k) { case 0xe0: key = 1;kf = 1; break; case 0xd0: key = 2;kf = 1; break; case 0xb0: key = 3;kf = 1; break; case 0x70: key = 88;kf = 1; break; } } } return key; }
上面这一段是矩阵键盘的程序,通过改变P1口的值来进行行列检测,同时增加一个标志位kf来判断按键是否松开。有了按键驱动下面就可以编写密码输入的函数了:
void input() //密码输入函数 { keyboard(); if(key!=88) { while(kf) { keyboard(); } s = (char)key; s = s | 0x30; lcd_pos(d); write_date(s); in[i] = key; i++; d++; key = 88; } }
在密码输入函数里我们调用键盘扫描函数,当有按键按下时我们就将对应的键值保存到输入密码的数组里,然后将每一个输入的按键的键值显示在LCD的显示屏上。LCD的驱动程序会在下面讲解。
现在要开始编写LCD的驱动用来显示输入的数字,我们首先需要两个函数,分别给LCD发送数据和指令,程序如下:
void write_com(uchar com) //LCD写指令 { P0=com; rs=0; lcden=0; delay(10); lcden=1; delay(10); lcden=0; } void write_date(uchar date) //LCD写数据 { P0=date; rs=1; lcden=0; delay(10); lcden=1; delay(10); lcden=0; }
我们可以通过写数据的函数发送给LCD要显示的数据,可以通过写命令函数向LCD发送指令来对LCD进行相应的设置,相关的指令大家可以自行到网上查阅,以下列出的函数分别用来改变光标位置,LCD初始化设置和清屏。
void lcd_pos(uchar pos) //设置LCD显示位置 { write_com(pos | 0x80); } void init() //LCD初始化 { write_com(0x38); delay(20); write_com(0x0f); delay(20); write_com(0x06); delay(20); write_com(0x01); delay(20); write_com(0x0c); delay(20); } void clear() //LCD清屏 { write_com(0x01); delay(20); }
接下来我们可以对输入的密码进行判断,
void judge() //密码判断函数 { if(i==6) { for(f = 0;f<6;f++) { if(password[f] == in[f]) m++; } if(m==6) { es = 0; clear(); lcd_pos(0x03); write_dates("Welcome!"); delay(1200); clear(); lcd_pos(0x00); write_dates("Password:"); lcd_pos(0x45); write_dates("******"); } else { es++; clear(); lcd_pos(0x04); write_dates("Error!"); delay(1200); if(es == 3) { lcd_pos(0x45); write_dates("WARNING"); delay(5000); es = 0; clear(); } lcd_pos(0x00); write_dates("Password:"); lcd_pos(0x45); write_dates("******"); } m = 0; i = 0; d = 0x45; } }
密码锁的密码为6位,当输入6位密码后我们就可以对密码进行判断,判断过程就是将输入密码的数组与保存的密码的数组通过循环进行比较,当输入密码正确后就会显示欢迎界面,等待一段时间再返回密码输入界面,如果密码输入错误则进入错误界面,然后返回密码输入界面,我们可以检测错误的次数如果错误次数太多可以进行类似延长等待时间等操作。
最后就是密码修改的操作。
void change() //修改密码函数 { if(mod==1) { lcd_pos(0x00); write_dates("OldPassword:"); input(); if(i==6) { for(f = 0;f<6;f++) { if(password[f] == in[f]) m++; } if(m==6) { mod=2; clear(); lcd_pos(0x45); write_dates("******"); } else { clear(); lcd_pos(0x04); write_dates("Error!"); delay(1200); lcd_pos(0x00); write_dates("Password:"); lcd_pos(0x45); write_dates("******"); mod=0; } m = 0; i = 0; d = 0x45; } } if(mod==2) { lcd_pos(0x00); write_dates("NewPassword:"); input(); if(i==6) { for(f = 0;f<6;f++) { password[f] = in[f]; } lcd_pos(0x44); write_dates("success!"); delay(1200); clear(); lcd_pos(0x00); write_dates("Password:"); lcd_pos(0x45); write_dates("******"); i = 0; mod = 0; d = 0x45; } } }
修改密码需要我们先输入正确密码,然后会进入修改界面,再次输入新密码就可以保存了。过程就是用循环来更新数组内的值,这样一个简单的密码锁就做好了,不过这样的锁有一个缺点,就是设置的密码不会保存,等单片机再次上电后就会恢复到最初始的密码,要想在断电后继续保存密码,我们可以使用EEPROM来进行密码的保存,由于篇幅原因,我会在之后单独介绍EEPROM的读写操作。感谢各位的观看。
点“阅读原文”,文章!
相关产品推荐:树莓派4B 现货,268元起!