基于FPGA的电子密码锁

实现的功能

1、 设计制作一个数字密码锁,共有8位密码,要求该密码是字母与数字的结合。输入密码由LCD显示
2、 系统上电后,8位初始密码为0000_0000.
3、 输入8位破解密码,输入完毕后,按确认键,若输入密码与破解密码匹配,则开锁成功,点亮第一位led(长亮)蜂鸣器响一声。解锁成功后按设置密码键可重新设置密码。若输入密码与破解密码不匹配,则开锁不成功,点亮第二位led(长亮),再次输入破解密码。若下次输入正确,则点亮第一位led(长亮),熄灭第二位led,若输入密码3次以后,仍未解锁,则第二位led长亮,第三位led长亮并锁闭键盘。
4、 按下复位键,解锁键盘,熄灭第一位、第二位和第三位led,并可重新操作第三步。

硬件要求:

LCD1602一块(16引脚的);
FPGA开发板。这里我采用的是正点原子的新起点开发板,使用其他的开发板要记得自个分配引脚。使用的是正点原子新起点开发板的话可以按下面连接LCD1602和分配引脚:

注意,板子上只有四个按键0~3,还需要额外接两个按键4和5。按键key_in[6]没有用到,预留出来了。外接按键要按下图接,上拉电阻为10K,电压3.3v

LCD1602的工作原理:
LCD1602在玩过单片机的应该是较早接触的字符型液晶显示器了,一般来说,LCD1602有16引脚,也有14引脚的,16脚的相比14脚的多了背光电源A(15脚)和地线K(16脚)。我手里这里使用的是16脚的,接线图如下:RS到DB7按上图的引脚分配表接开发板上

对应到LCD1602的引脚上分别是:

1、VSS接电源地。

2、VDD接+5V。

3、VO是液晶显示的偏压信号,可接电位器,改变背光,电压过高和过低会看不清字符。
4、RS是命令/数据选择引脚,接FPGA的一个I/O,当RS为低电平时,选择命令;当RS为高电平时,选择数据。

5、RW是读/写选择引脚,接FPGA一个I/O,当RW为低电平时,向LCD1602写入命令或数据;当RW为高电平时,从LCD1602读取状态或数据。如果不需要进行读取操作,可以直接将其接GND。(这里我接的是IO口)
共有四种状态:注意FPGA速度很快,在控制LCD1602时注意延时
输入RS=0,RW=1,E=高脉冲。输出:D0—D7为状态字。(读命令)
输入RS=1,RW=1,E=高脉冲。输出:D0—D7为数据。 (读数据)
输入RS=0,RW=0,E=高脉冲。输出:无。 (写命令)
输入RS=1,RW=0,E=高脉冲。输出:无。(写数据)

6)E,执行的使能引脚,接FPFA的一个I/O。

7)D0—D7,并行数据输入/输出引脚,接FPGA的的8个I/O口。

8)A背光正极,可接到VCC。

9)K背光负极,接GND

LCD1602可以显示16列2行的字符,LCD1602显示的原理 跟 8* 8的点阵显示原理很相似,1602显示字符的原理也是8*8的点组成的,例如我们要显示一数字0:
通过点亮相应的点就可以,但与点阵不同的是,有些LCD1602不需要取字模,因为其内部自带了字库,通过对照ASCALL码表就可以显示相应的数字:例如还是要显示数字0的话,我们只需要往DB0-DB7写入数值48,就可显示数字0

常用的ASCALL对照表:


LCD1602的工作原理可自行百度或参考:LCD1602工作原理

效果图:

开始状态:

密码错误:

密码正确

最后,附上代码:这里没有采用例化语句,而是将所有的程序放在一个工程里了,这样很方便的将程序复制到自行创建工程使用,到时再自行分模块使用。(程序显示会有一小BUG,但不影响使用,可自行优化)

module LCD1602 (rst,key_in,clk,rw,rs,en,data,led,led1,led2,led3,bee,);input clk,rst;    //CLK 50M,RSTw为复位信号/***********************给变量赋初值************************/
/***************************/
initial A<=8'd48;//初始密码 0000——0000,d48为0的ASCALL值
initial B<=8'd48;
initial C<=8'd48;
initial D<=8'd48;
initial E<=8'd48;
initial F<=8'd48;
initial G<=8'd48;
initial H<=8'd48;
/****************************/
initial bee=0;
initial bee_flag=0;
initial p=0;
/***************************/
initial i<=1;
initial led=0;
initial led1=0;
initial led2=0;
initial led3=0;
initial flag=0;
initial xianshi<=8'd16;  //让初始化完以后,就显示空字符
initial add<=8'h80;      //让初始化显示的地址
initial shuzi<=8'd57;    //让初始化完以后,数字变量为9,ascll码值为57,
initial zimu<=8'd122;    //为什么是9,因为按键按下后,数字会加一,9加一变为10,10以后跳会0,//所以第一按按键显示0  //让初始化字母为小写z
/**********************************************************/ /*******************************************************************************************************************************************//****************************************************************LCD的初始化函数************************************************************//******************************************************************************************************************************************//**********计数器函数用于在状态机中做延时使用***************************/
/********************************************************************/ reg [31:0]count;always @(posedge clk )  beginif(!rst)count<=0;else begincount<=count+1;if(count==2_000_001)begincount<=0;end endend /**********************************状态定义*************************************/parameter  state0  =6'h00,  //设置8位格式,2行显示,5*7                 8'h38; state1  =6'h01,  //开显示,开光标,闪烁  8'h0e    关光标,不闪烁 8'h0cstate2  =6'h02,  //输入数据光标右移,显示字符不移动            8'h06state3  =6'h03,  //清屏     8'h01state4  =6'h04,  //显示的地址  addstate5  =6'h05;  //显示的字符
/********************************************************************************/ output rs,en,rw;  //LCD控制使能端,rs=0时为写命令,rs=1;为写数据,en为LCD的E引脚,rw=0时,为写,rw=1为读数据(读数据没有用到,所以rw始终为0)output [7:0] data;//输出LCD显示的字符//LCD的D0到D7引脚reg rs,en_sel;    //OUTput的变量要为定义为reg类型,en_sel为LCD  E引脚的寄存器变量,最终为E=en_selreg [7:0]data;    reg [7:0]add;     //LCD字符显示的地址reg [7:0] next;    //next为状态定义reg[3:0]lcd_flag; // lcd_flag=0表示LCD正在写入字符,lcd_flag=1;表示LCD写入数据完成always @(posedge clk,negedge rst)beginif(!rst)beginnext<=state0;lcd_flag=0;endelsebegincase(next)state0 :begin if(count<1000_000)begin rs=0;en_sel=1;data=8'h38;end //rs=0;为写命令;命令值为H38,设置8位格式,2行,5*7,LCD的使能端E为1(en_sel=1); if(count>1000_000)begin en_sel=0;end                  //LCD的使能端E为0(en_sel=0),下降沿的时候把数据读进去; if(count>2000_000)begin next<=state1;end             //延时一段时间10MS,LCD速度较慢必须延时endstate1 :begin if(count<1000_000)begin rs=0;en_sel=1;data=8'h0e;end if(count>1000_000)begin en_sel=0;end if(count>2000_000)begin next<=state2;end endstate2 :begin if(count<1000_000)begin rs=0;en_sel=1;data=8'h06;end if(count>1000_000)begin en_sel=0;end if(count>2000_000)begin next<=state3;end endstate3 :begin if(count<1000_000)begin rs=0;en_sel=1;data=8'h01;end if(count>1000_000)begin en_sel=0;end if(count>2000_000)begin next<=state4;end end    state4 :begin if(count<1000_000)begin lcd_flag=0; rs=0;en_sel=1;data=add;end //lcd_flag=0表示LCD正在写入一个数据,if(count>1000_000)begin en_sel=0;end                           // 此时的数据应该保持稳定if(count>2000_000)begin next<=state5;end end state5 :begin if(count<1000_000)begin rs=1;en_sel=1;data=xianshi;end //rs=1;为写数据,xinashi是要显示的数据if(count>1000_000)begin en_sel=0;lcd_flag=1;end       //lcd_flag为1时表示数据写入完成,可以写入下一个数据if(count>2000_000)begin next<=state4;end end default:   next<=state0; endcaseendend/*****************************************************************************************************************************************************/*******************************************************************以下函数为密码锁功能实现*********************************************************//*****************************************************************************************************************************************************/*********计数器函数用于在蜂鸣器中做延时***********************/
/************************************************************/  reg [31:0]count2; // CLK 分频计数器output bee;       //蜂鸣器控制端,bee为高电平时蜂鸣器响reg bee;      reg bee_flag;    //蜂鸣器使能标志reg bee_clk;    //蜂鸣器时钟reg p;          //蜂鸣器响标志always @(posedge clk )  beginif(!rst)count2<=0;elsecount2<=count2+1;if(count2==50_000_000)beginbee_clk=1;      endif(count2==50_900_000)beginbee_clk=0;endif(count2==51_000_000)begincount2<=0;endend /*****************************************************************************************///按键检测函数//========================================================================================reg [31:0]count1; // CLK 分频计数器
always @(posedge clk or negedge rst) //检测时钟的上升沿和复位的下降沿
beginif(!rst)                 //复位信号低有效count1 <= 32'd0;         //计数器清 0elsebeginif(count1 ==32'd999_999) //20ms 扫描一次按键,20ms 计数(50M/50-1=999_999)begincount1 <= 1'b0;          //计数器计到 20ms,计数器清零key_scan <= key_in;      //采样按键输入电平endelsecount1 <= count1 + 1'b1; //计数器加 1end
end
//====================================================
// 按键信号锁存一个时钟节拍
//====================================================
input [6:0] key_in;//按键的定义 key0为数字0-9输入 key1为大小写字母输入 key2为输入密码的下一位 key3为确定键
reg [6:0] key_scan_r;
reg [6:0] key_scan;
always @(posedge clk)
key_scan_r <= key_scan;//利用非阻塞赋值实现下降沿检测
wire [6:0] flag_key = key_scan_r[6:0] & (~key_scan[6:0]); //检测按键的下降沿/****************************************************************************************/
//密码输入处理函数
/**************************************************************************************/
reg key_flag; //修改密码标记位
reg [3:0]i,flag;//i用于指示密码的第几位,flag用于判断判断密码输入错误的次数,3次后,键盘锁定,不可以输入数据
reg[7:0]xianshi,shuzi,zimu;//定义xianshi为显示的变量,shuzi,zimu显示的暂存变量
reg add_flag;//地址改变标志位output led,led1,led2,led3;//LED灯的定义
reg led,led1,led2,led3; reg[7:0] a,b,c,d,e,f,g,h,A,B,C,D,E,F,G,H;//存储输入的密码和设定密码的变量always @ (posedge clk or negedge rst)
beginif (!rst) //复位信号低有效begin key_flag=0;shuzi<=8'd57;  //复位为数字9zimu<=8'd122;  //复位为小写字母zxianshi<=8'd16;//复位为空字符add=8'h80;    //复位第一行第一个显示i=1;          flag=0;led=0;led1=0;led2=0;led3=0;bee=0;add_flag=0;a=0;b=0;c=0;d=0;e=0;f=0;g=0;h=0;end else if(flag<=2)  //flag为错误密码的次数,等于3if条件不满足,键盘不能使用beginif(lcd_flag&&add_flag)//如果显示的地址发生变化且LCD显示完成(lcd_flag=1),才显示为空字符,beginxianshi=8'd16;add_flag=0;endif ( flag_key[0] )begin  shuzi=shuzi+1'b1;if(shuzi==8'd58)shuzi=8'd48;xianshi=shuzi; //按键 KEY0 按下时,数字加一,第一次按下时,// 初始shuzi为9,按下后加一,等于10,就自动变成0if(key_flag==0) //  key_flag==0表示输入密码状态begin                                  if(i==1)a=shuzi;                                                     if(i==2)b=shuzi;if(i==3)c=shuzi;if(i==4)d=shuzi;if(i==5)e=shuzi;if(i==6)f=shuzi;if(i==7)g=shuzi;if(i==8)h=shuzi;endif(key_flag==1) //  key_flag==1表示设置密码状态,i表示给第i位密码赋值begin                                if(i==1)A=shuzi;                                                     if(i==2)B=shuzi;if(i==3)C=shuzi;if(i==4)D=shuzi;if(i==5)E=shuzi;if(i==6)F=shuzi;if(i==7)G=shuzi;if(i==8)H=shuzi;endend if ( flag_key[1] ) begin zimu=zimu+1;if(zimu==91)zimu=8'd97;if(zimu==8'd123)zimu=8'd65;xianshi=zimu;//65为A,97为a,122为小写字母zif(key_flag==0) //  key_flag==0表示输入密码状态beginif(i==1)a=zimu;                                                     if(i==2)b=zimu;if(i==3)c=zimu;if(i==4)d=zimu;if(i==5)e=zimu;if(i==6)f=zimu;if(i==7)g=zimu;if(i==8)h=zimu; endif(key_flag==1) //  key_flag==1表示设置密码状态begin                                  if(i==1)A=zimu;                                                     if(i==2)B=zimu;if(i==3)C=zimu;if(i==4)D=zimu;if(i==5)E=zimu;if(i==6)F=zimu;if(i==7)G=zimu;if(i==8)H=zimu;endend if ( flag_key[2] ) begin add_flag<=1;i=i+1;if(i>7)i=8; //密码的位数与显示的地址应该同步add<=add+1'b1;    //按键 KEY2 值变化时,地址显示加一,字符右移一位if(add>8'h86)add<=8'h87;//到达第8后不再加,因为密码为8位,可根据需要修改shuzi<=8'd57;zimu<=8'd122;endif ( flag_key[3] )begin        //按键 KEY3 按下时,一位一位的比对密码if(a==A)beginif(b==B)beginif(c==C)beginif(d==D)beginif(e==E)beginif(f==F)beginif(g==G)beginif(h==H)beginled=1;led1=0;bee_flag=1;bee=1;endelse begin led1=1;led=0; endendelse begin led1=1;led=0; endendelse begin led1=1;led=0; endendelse begin led1=1;led=0; endendelse begin led1=1;led=0; endendelse begin led1=1;led=0; endendelse begin led1=1;led=0; endendelse begin led1=1;led=0; endif(led==1)flag=0;if(led1==1)flag=flag+1;if(flag==3)led2=1;endif ( flag_key[4] )begin //如果密码输入正确,按下此按键可以修改密码 if(led==1)beginkey_flag=~key_flag;if(key_flag==1)led3=1;elseled3=0;endend if ( flag_key[5] )begin//按下此按键可以退回上一位xianshi=8'd16; //显示为空字符shuzi<=8'd57;  //复位为数字9zimu<=8'd122;  //复位为小写字母z add<=add-1;if(add<8'h80)add<=8'h87;i=i-1;if(i==0)i=8;end//****************蜂鸣器代码*******************************//下面这段代码实现的功能为:密码输入正确后,蜂鸣器响一声//(当bee_clk=0,bee_flag=1时(也就是密码输入正确时)蜂鸣器在响)if(bee_clk&&bee_flag==1)//当蜂鸣器时钟bee_clk=1且蜂鸣器标志位bee_flag为1时beginbee=0;                   //蜂鸣器停止p=1;                    //p=1用来表示蜂鸣器已经响了endelse if(p==1)beginp=0;          //清零等待下一次响bee_flag=0;   //清零等待下一次密码输入正确end//****************************************************************
end
endassign en=en_sel; assign rw=0;//rw为0表示LCD的rw引脚为低电平,此时为写,rw为1时读
endmodule

基于FPGA的电子密码锁相关推荐

  1. 基于FPGA的电子计算器设计(下)

    今天给大侠带来基于FPGA的电子计算器设计,由于篇幅较长,分三篇.今天带来第三篇,下篇,话不多说,上货. 导读 本篇介绍了一个简单计算器的设计,基于 FPGA 硬件描述语言 Verilog HDL,系 ...

  2. 基于FPGA的电子计算器设计(上)

    今天给大侠带来基于FPGA的电子计算器设计,由于篇幅较长,分三篇.今天带来第一篇,上篇,话不多说,上货. 导读 本篇介绍了一个简单计算器的设计,基于 FPGA 硬件描述语言 Verilog HDL,系 ...

  3. 基于单片机的密码锁c语言设计程序,基于单片机的电子密码锁及程序

    <基于单片机的电子密码锁及程序>由会员分享,可在线阅读,更多相关<基于单片机的电子密码锁及程序(17页珍藏版)>请在人人文库网上搜索. 1.基于单片机的电子密码锁设计摘要随着科 ...

  4. 基于stm32的c语言程序设计,基于stm32的电子密码锁设计 main.c 代码奉上,做课设的直接用...

    电子密码锁设计 **功能:支持3~20位的密码设置,初始密码为123456:若要重设密码,需先输入正确密码开锁. ** 正常显示情况下,按下确认键上锁:按下密码键,开始输入密码. **接线:PE[0. ...

  5. 基于8051的电子密码锁程序

    /**************************************** 功能:当电源接通时,LED灯以1S闪烁,键盘上 可输入2位密码与预设密码比对,如相符则LED常 亮,如不符仍需输入密 ...

  6. 基于FPGA的电子万年历设计

    1.软件版本 quartusii12.1 2.系统描述 系统的整个结构框图: 然后,设置控制输入有5个脚,分析功能如下所示: i_Function_Controller=0:显示年月日 i_sel:选 ...

  7. 基于FPGA的数字密码锁电路设计(含程序)

    录 题目 设计思路 代码设计 题目 (1)4个按键分别设置4位数码管上的显示数字,当按键设置的数字与设置的4位密码一致时,蜂鸣器响,表示锁打开: (2)具备通过按键手动修改数字密码的功能: (3)具备 ...

  8. 基于单片机的电子密码锁1602液晶显示设计

    文末下载完整资料 仿真 程序 //×÷ÕßQQ:497259320 //ÍøÕ¾http://proteus.5d6d.com //ÄÏÑôÀí¹¤Ñ§Ôº //ѧϰÊÇÒÅÍüµÄ×îºÃµÄ· ...

  9. 基于FPGA的电子日历设计

    本设计是本学期的课程设计,也没有正式上过课,全凭自学摸索完成本课程设计,在摸索的过程中也看了csdn上众多博客,给予了本人很大的帮助,本人做完也前来分享.若有不对错误之处也请大家多多理解指正.本设计可 ...

最新文章

  1. 面向对象设计原则_聊聊面向对象的6大设计原则
  2. php 调用url field,使用 PHP curl 调用 API,如何传递如下格式的 POSTFIELD?
  3. MySQL隐式转化整理
  4. Django实战(11):修改Model类
  5. (2) 第二章 WCF服务与数据契约 服务契约详解(二)- 如何引用WCF提供的服务
  6. 为什么工作10年你的工资还不如新来的实习生
  7. memcached 安装小结-1
  8. B君的圆锥(51Nod-1629)
  9. oracle如何杀掉表死锁,oracle杀死死锁的方法
  10. python123九宫格输入_使用python PIL库实现简单验证码的去噪方法步骤
  11. 在C++Builder2010中配置OpenCV2.2
  12. Windows server 2012远程桌面会话主机和远程桌面授权,server2012
  13. wps中的相交_如何在wps中添加交叉引用 - 卡饭网
  14. word批量转换为pdf python脚本
  15. 在做开关电路时,三极管限流电阻该如何选择?
  16. CCF优秀博士学位论文奖初评名单出炉!清华入选4人,数量第一
  17. DAPLink-Firmware
  18. 梭子鱼网络:2018年网络安全威胁预测
  19. FlinkSQL字段血缘解决方案及源码
  20. 《漫画英国》的读书笔记感想4069字

热门文章

  1. 一篇文章带你了解云计算
  2. .Net 7 CLR和ILC编译函数过程
  3. 美通企业日报 | IMAX中国票房纪录创年度新高;上海迪士尼将迎来黄色小狗可琦安...
  4. BZOJ 1933 [Shoi2007]Bookcase 书柜的尺寸
  5. html a text decoration,你未必知道的CSS小知识:text-decoration属性变成了属性简写
  6. 机器学习100天(十七):017 逻辑回归梯度下降
  7. 常见的五种排序,冒泡排序,选择排序,插入排序,并归排序,快速排序
  8. 7.博客系统| 评论功能(文章评论,评论的评论)
  9. Google智能家居控制ESP8266
  10. linux里的文件服务