数字密码锁(下)

上篇整理了前两个模块,可以做出来功能按键以及数字按键的信号,接着就要利用这些信号对密码锁进行控制。

3、控制模块

第三个模块为控制模块,主要实现的是一些信号的处理,也是整个工程的重中之重,主要完成了密码的接收、核对、更改、以及确认
首先就是接收从功能分配模块接受传送过来的信号,包括:

input clk;
input check;
input [3:0] number_key;
input state_lock;  //密码锁开启/关闭状态
input reset;
input clear_flag;  //清零状态
input lock;
input rece_flag;   //密码输入标志
input [3:0] rece_cnt;

接着就考虑输出的信号都有哪些。与控制模块的相接的就是最后的显示模块了,所以要考虑与显示相关的信号有哪些:

output reg  led;
output reg [3:0] disp_in1;
output reg [3:0] disp_in2;
output reg [3:0] disp_in3;
output reg [3:0] disp_in4;
output reg beep;

做好接口以后,就开始做内部的逻辑电路设计。
首先做一个密码的初始化,即刚开机时候的密码:

initialbeginpassword1<=4'd1;    //初始密码为1234password2<=4'd2;password3<=4'd3;password4<=4'd4;end

然后接下来的设计主要分为三块:一是密码的接收,二是密码的判断,三是密码的更改
一共定义两组密码变量,一组是存储在寄存器中的真正密码,一组是用于接收按键输入的预备密码
下面为密码的接收部分:

always@(posedge clk)if(state_lock==1) begincase(reset_state)0:if(clear_flag==1)  beginpreword1<=4'd0;preword2<=4'd0;preword3<=4'd0;preword4<=4'd0;endelse begincase(rece_cnt)0:beginpreword1<=4'd0;preword2<=4'd0;preword3<=4'd0;preword4<=4'd0;end1:preword1<=number_key;2:preword2<=number_key;3:preword3<=number_key;4:preword4<=number_key;default:beginpreword1<=preword1;preword2<=preword2;preword3<=preword3;preword4<=preword4;endendcaseend1:beginpreword1<=password1;preword2<=password2;preword3<=password3;preword4<=password4;endendcase end

当输入的预备密码与存储在寄存器中的真正密码一致时,按下确认键才会打开密码锁

密码判断部分:

/****************密**码**核**实***************/
always@(posedge clk)beginif(check==1)  confirm<=1;else if(clear_flag==1) confirm<=0;else if(state_lock==0) confirm<=0;else confirm<=confirm;endassign right0[0]=(password1==preword1);
assign right0[1]=(password2==preword2);
assign right0[2]=(password3==preword3);
assign right0[3]=(password4==preword4);always@(posedge clk)if(state_lock==1) beginif(confirm==1)  beginif(right0==4'b1111)beginled<=0; //输入密码正确指示灯亮right<=1;endelse beginled<=1;right<=0;end endelse if(reset_state==1)beginled<=0;right<=1;endelse if((reset_state==0)&&(clear_flag==1))beginled<=1;right<=0;endelse beginled<=led;right<=right;endend else beginled<=1;right<=0;end

由于只有三次输入密码的机会,所以也要对密码的确认次数进行限制,根据确认的次数以及密码的正确与否来对输入密码次数做出限制:

//*************密码确认次数控制****************//
always@(posedge confirm)beginif(state_lock==1) beginif(right==0) beginif(w_cnt==2'b11) w_cnt<=2'b00;else w_cnt<=w_cnt+2'b1;endelse w_cnt<=2'b00;    endelse w_cnt<=2'b00;    end

密码更改部分:

/*************更**改**密**码**********************/always@(posedge clk)if(right==1) begin     //输入密码正确才可进入修改密码状态if(reset==1) reset_state<=1;else if(lock==1) reset_state<=0;else reset_state<=reset_state;endelse reset_state<=0;always@(posedge clk)if(state_lock==1) begincase(reset_state)1: if(clear_flag==1) beginpassword1<=4'd0;password2<=4'd0;password3<=4'd0;password4<=4'd0;endelse begincase(rece_cnt)0: beginpassword1<=password1;password2<=password2;password3<=password3;password4<=password4;end1:password1<=number_key;2:password2<=number_key;3:password3<=number_key;4:password4<=number_key;default:beginpassword1<=password1;password2<=password2;password3<=password3;password4<=password4;endendcaseend0:beginpassword1<=password1;password2<=password2;password3<=password3;password4<=password4;endendcaseendalways@(posedge clk)if(state_lock==1) begindisp_in1<=preword1;disp_in2<=preword2;disp_in3<=preword3;disp_in4<=preword4;end

该模块完整程序

module lock_ctrl(clk,reset,clear_flag,lock,rece_cnt,rece_flag,check,number_key,led,beep,disp_in1,disp_in2,disp_in3,disp_in4,state_lock);
input clk;
input check;
input [3:0] number_key;
input state_lock;  //密码锁开启/关闭状态
input reset;
input clear_flag;  //清零状态
input lock;
input rece_flag;   //密码输入标志
input [3:0] rece_cnt;output reg  led;
output reg [3:0] disp_in1;
output reg [3:0] disp_in2;
output reg [3:0] disp_in3;
output reg [3:0] disp_in4;
output reg beep;        reg [3:0] preword1;    //输入准密码reg [3:0] preword2; reg [3:0] preword3; reg [3:0] preword4; reg [3:0] password1;  //设定密码reg [3:0] password2;  reg [3:0] password3;  reg [3:0] password4; reg warnning;  //密码错误三次警告
reg reset_state;  //重置密码状态reg right;   //密码输入正确标志
reg   clk_beep;  //蜂鸣器驱动脉冲
reg [1:0] w_cnt;   //输入密码次数计数器
reg [15:0]   delay_beep; //延时计数器
reg confirm;  //密码确认延时一个时钟
reg [23:0]   cnt_beep;  //分频计数器
wire [5:0] right0;initialbeginpassword1<=4'd1;    //初始密码为1234password2<=4'd2;password3<=4'd3;password4<=4'd4;led<=1;warnning<=0;beep<=0;w_cnt=2'b10;right=0;delay_beep<=0;cnt_beep<=0;clk_beep=0;end
/**********密**码**核**实********/
always@(posedge clk)beginif(check==1)  confirm<=1;else if(clear_flag==1) confirm<=0;else if(state_lock==0) confirm<=0;else confirm<=confirm;endassign right0[0]=(password1==preword1);
assign right0[1]=(password2==preword2);
assign right0[2]=(password3==preword3);
assign right0[3]=(password4==preword4);always@(posedge clk)if(state_lock==1) beginif(confirm==1)  beginif(right0==4'b1111)beginled<=0; //输入密码正确指示灯亮right<=1;endelse beginled<=1;right<=0;end endelse if(reset_state==1)beginled<=0;right<=1;endelse if((reset_state==0)&&(clear_flag==1))beginled<=1;right<=0;endelse beginled<=led;right<=right;endend else beginled<=1;right<=0;end//*****密码确认次数控制**********//
always@(posedge confirm)beginif(state_lock==1) beginif(right==0) beginif(w_cnt==2'b11) w_cnt<=2'b00;else w_cnt<=w_cnt+2'b1;endelse w_cnt<=2'b00;    endelse w_cnt<=2'b00;    end//*********输入三次错误*********//always@(posedge clk)    //当第四次输入,触发警报if(state_lock==1) beginif(w_cnt==2'b11)  warnning<=1;else warnning<=0;endelse warnning<=0;always@(posedge clk)   //驱动蜂鸣器if(warnning==1) beginif(cnt_beep<=5_00)cnt_beep<=cnt_beep+24'd1;else begincnt_beep<=24'd0;clk_beep<=~clk_beep;endendelse cnt_beep<=24'd0;always@(posedge clk_beep)  //蜂鸣持续时间if(delay_beep<=16'd800)  beginbeep=~beep;delay_beep<=delay_beep+16'd1;endelse beginif(w_cnt==2'b11)delay_beep<=16'd8001;else delay_beep<=16'd0;end/*************密**码**接**收***************/
always@(posedge clk)if(state_lock==1) begincase(reset_state)0:if(clear_flag==1)  beginpreword1<=4'd0;preword2<=4'd0;preword3<=4'd0;preword4<=4'd0;endelse begincase(rece_cnt)0:beginpreword1<=4'd0;preword2<=4'd0;preword3<=4'd0;preword4<=4'd0;end1:preword1<=number_key;2:preword2<=number_key;3:preword3<=number_key;4:preword4<=number_key;default:beginpreword1<=preword1;preword2<=preword2;preword3<=preword3;preword4<=preword4;endendcaseend1:beginpreword1<=password1;preword2<=password2;preword3<=password3;preword4<=password4;endendcase end/**********更**改**密**码*****************/always@(posedge clk)if(right==1) begin     //输入密码正确才可进入修改密码状态if(reset==1) reset_state<=1;else if(lock==1) reset_state<=0;else reset_state<=reset_state;endelse reset_state<=0;always@(posedge clk)if(state_lock==1) begincase(reset_state)1: if(clear_flag==1) beginpassword1<=4'd0;password2<=4'd0;password3<=4'd0;password4<=4'd0;endelse begincase(rece_cnt)0: beginpassword1<=password1;password2<=password2;password3<=password3;password4<=password4;end1:password1<=number_key;2:password2<=number_key;3:password3<=number_key;4:password4<=number_key;default:beginpassword1<=password1;password2<=password2;password3<=password3;password4<=password4;endendcaseend0:beginpassword1<=password1;password2<=password2;password3<=password3;password4<=password4;endendcaseendalways@(posedge clk)if(state_lock==1) begindisp_in1<=preword1;disp_in2<=preword2;disp_in3<=preword3;disp_in4<=preword4;endendmodule 

4、显示模块

控制模块完成了工程的主要内容,显示模块只需要将数值显示出来即可
首先,还是先定义接口:

 input clk;input state_lock;input [2:0] rece_cnt;input [3:0] disp_in1; input [3:0] disp_in2;input [3:0] disp_in3;input [3:0] disp_in4;
output reg [7:0] dxuan;
output reg [5:0] wxuan;

接着明确该模块内的主要任务:
1、能显示输入的数字
2、最新输入的数字总是显示在最右侧
基于这两点,对程序大体部分进行划分。首先是做一个段数码管的显示部分,即八段数码管能显示正确的数值。对数字0-9进行八段数码管的定义:

//*************数码管数值定义******************//
parameter disp0=8'b1100_0000;
parameter disp1=8'b1111_1001;
parameter disp2=8'b1010_0100;
parameter disp3=8'b1011_0000;
parameter disp4=8'b1001_1001;
parameter disp5=8'b1001_0010;
parameter disp6=8'b1000_0010;
parameter disp7=8'b1111_1000;
parameter disp8=8'b1000_0000;
parameter disp9=8'b1001_0000;
parameter disp10=8'b1011_1111;

根据输入的值不同,让段数码管显示不同的数值:

always@(posedge clk)begincase(cnt_symin)4'd1:dxuan<=disp1;4'd2:dxuan<=disp2;4'd3:dxuan<=disp3;4'd4:dxuan<=disp4;4'd5:dxuan<=disp5;4'd6:dxuan<=disp6;4'd7:dxuan<=disp7;4'd8:dxuan<=disp8;4'd9:dxuan<=disp9;4'd0:dxuan<=disp0;4'd10:dxuan<=disp10;default:dxuan<=disp0;endcaseend

其中,cnt_symin变量就需要根据不同的情况进行自动变更,利用case语句根据输入密码的位数来切换数码管显示的数字(即使输最新输入的密码显示在最右侧):

always@(posedge clk)if(state_lock==1) begin   //密码锁开关打开case(rece_cnt)3'd0:begincase(disp_state)2'd0:begin wxuan<=4'b0111; cnt_symin<=4'd0;end2'd1:begin wxuan<=4'b1011; cnt_symin<=4'd0;end2'd2:begin wxuan<=4'b1101; cnt_symin<=4'd0;end2'd3:begin wxuan<=4'b1110; cnt_symin<=4'd0;endendcaseend3'd1:begincase(disp_state)2'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in1;end2'd1:begin wxuan<=4'b1011; cnt_symin<=4'd0;end2'd2:begin wxuan<=4'b1101; cnt_symin<=4'd0;end2'd3:begin wxuan<=4'b1110; cnt_symin<=4'd0;endendcaseend3'd2:begincase(disp_state)2'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in2;end2'd1:begin wxuan<=4'b1011; cnt_symin<=disp_in1;end2'd2:begin wxuan<=4'b1101; cnt_symin<=4'd0;end2'd3:begin wxuan<=4'b1110; cnt_symin<=4'd0;endendcaseend3'd3:begincase(disp_state)3'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in3;end3'd1:begin wxuan<=4'b1011; cnt_symin<=disp_in2;end3'd2:begin wxuan<=4'b1101; cnt_symin<=disp_in1;end3'd3:begin wxuan<=4'b1110; cnt_symin<=4'd0;endendcaseend3'd4:begincase(disp_state)3'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in4;end3'd1:begin wxuan<=4'b1011; cnt_symin<=disp_in3;end3'd2:begin wxuan<=4'b1101; cnt_symin<=disp_in2;end3'd3:begin wxuan<=4'b1110; cnt_symin<=disp_in1;endendcaseenddefault:begincase(disp_state)2'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in4;end2'd1:begin wxuan<=4'b1011; cnt_symin<=disp_in3;end2'd2:begin wxuan<=4'b1101; cnt_symin<=disp_in2;end2'd3:begin wxuan<=4'b1110; cnt_symin<=disp_in1;endendcaseendendcaseendelse wxuan<=4'b1111;    

由于采用动态数码管的显示,所以需要对位数码管进行不断的切换,需要做一个分频模块对每位数码管循环显示:

/*********************分频*****************/always@(posedge clk)  //位数码管切换控制beginif(count<28'd20_0000)count<=count+28'd1;else begincount<=28'd0;if(disp_state<=2'd3)  disp_state<=disp_state+1;else disp_state<=0;endend

该模块完整程序:

module display(clk,state_lock,rece_cnt,disp_in1,disp_in2,disp_in3,disp_in4,dxuan, wxuan);input clk;input state_lock;input [2:0] rece_cnt;input [3:0] disp_in1; input [3:0] disp_in2;input [3:0] disp_in3;input [3:0] disp_in4;
output reg [7:0] dxuan;
output reg [5:0] wxuan;reg [27:0] count;  //位数码管分频计数器reg [1:0] disp_state;  //位数码管切换状态
reg [3:0] cnt_symin;//*************数码管数值定义******************//
parameter disp0=8'b1100_0000;
parameter disp1=8'b1111_1001;
parameter disp2=8'b1010_0100;
parameter disp3=8'b1011_0000;
parameter disp4=8'b1001_1001;
parameter disp5=8'b1001_0010;
parameter disp6=8'b1000_0010;
parameter disp7=8'b1111_1000;
parameter disp8=8'b1000_0000;
parameter disp9=8'b1001_0000;
parameter disp10=8'b1011_1111;/*********************分频*****************/always@(posedge clk)  //位数码管切换控制beginif(count<28'd20_0000)count<=count+28'd1;else begincount<=28'd0;if(disp_state<=2'd3)  disp_state<=disp_state+1;else disp_state<=0;endendalways@(posedge clk)if(state_lock==1) begin   //密码锁开关打开case(rece_cnt)3'd0:begincase(disp_state)2'd0:begin wxuan<=4'b0111; cnt_symin<=4'd0;end2'd1:begin wxuan<=4'b1011; cnt_symin<=4'd0;end2'd2:begin wxuan<=4'b1101; cnt_symin<=4'd0;end2'd3:begin wxuan<=4'b1110; cnt_symin<=4'd0;endendcaseend3'd1:begincase(disp_state)2'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in1;end2'd1:begin wxuan<=4'b1011; cnt_symin<=4'd0;end2'd2:begin wxuan<=4'b1101; cnt_symin<=4'd0;end2'd3:begin wxuan<=4'b1110; cnt_symin<=4'd0;endendcaseend3'd2:begincase(disp_state)2'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in2;end2'd1:begin wxuan<=4'b1011; cnt_symin<=disp_in1;end2'd2:begin wxuan<=4'b1101; cnt_symin<=4'd0;end2'd3:begin wxuan<=4'b1110; cnt_symin<=4'd0;endendcaseend3'd3:begincase(disp_state)3'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in3;end3'd1:begin wxuan<=4'b1011; cnt_symin<=disp_in2;end3'd2:begin wxuan<=4'b1101; cnt_symin<=disp_in1;end3'd3:begin wxuan<=4'b1110; cnt_symin<=4'd0;endendcaseend3'd4:begincase(disp_state)3'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in4;end3'd1:begin wxuan<=4'b1011; cnt_symin<=disp_in3;end3'd2:begin wxuan<=4'b1101; cnt_symin<=disp_in2;end3'd3:begin wxuan<=4'b1110; cnt_symin<=disp_in1;endendcaseenddefault:begincase(disp_state)2'd0:begin wxuan<=4'b0111; cnt_symin<=disp_in4;end2'd1:begin wxuan<=4'b1011; cnt_symin<=disp_in3;end2'd2:begin wxuan<=4'b1101; cnt_symin<=disp_in2;end2'd3:begin wxuan<=4'b1110; cnt_symin<=disp_in1;endendcaseendendcaseendelse wxuan<=4'b1111;   always@(posedge clk)begincase(cnt_symin)4'd1:dxuan<=disp1;4'd2:dxuan<=disp2;4'd3:dxuan<=disp3;4'd4:dxuan<=disp4;4'd5:dxuan<=disp5;4'd6:dxuan<=disp6;4'd7:dxuan<=disp7;4'd8:dxuan<=disp8;4'd9:dxuan<=disp9;4'd0:dxuan<=disp0;4'd10:dxuan<=disp10;default:dxuan<=disp0;endcaseend
endmodule

总结

在做这个工程的时候,出现了各种各样的问题。解决时间最长的是矩阵键盘的模块,由于矩阵键盘的错误导致后续模块都无法正常工作。
现在虽然能实现大多数功能,但仍然不能保证他的功能都是完整无错的。逻辑很复杂,思维难免出现漏洞,所以倘若发现有不正确的地方,请不吝告知,好及时更改。

【注】个人学习笔记,请不吝赐教!

FPGA学习——数字密码锁(下)相关推荐

  1. FPGA学习——数字密码锁(上)

    基于FPGA的数字密码锁 一.简介 1.1设备要求 1.2 功能要求 二.工程分析: 三.具体程序: 顶层模块: 1.矩阵键盘扫描模块 2.功能划分模块 第三.第四模块在下篇中 四.总结: 一.简介 ...

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

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

  3. FPGA学习之 直接数字频率合成器(DDS)

    目录 FPGA学习之 直接数字频率合成器(DDS) FPGA学习之 直接数字频率合成器(DDS) DDS的原理: 直接数字频率合成器(Direct Digital Synthesizer, DDS)是 ...

  4. FPGA学习之 状态机实现数码管的数字时钟

    FPGA学习之 状态机实现数字时钟 开发板型号:EP4CE6F17C8 六位数码管原理图: 由图可知,数码管段选和片选均为低电平有效. 由于人眼的视觉残留,我们控制一定频率对每一位数码管进行刷新,就能 ...

  5. 基于FPGA的数字视频信号处理器设计(下)

    基于FPGA的数字视频信号处理器设计(下) 今天给大侠带来基于FPGA的数字视频信号处理器设计,由于篇幅较长,分三篇.今天带来第三篇,下篇,程序测试与运行.话不多说,上货. 导读 图像是用各种观测系统 ...

  6. FPGA设计/数字IC前端设计学习交流群

    FPGA设计/数字IC前端设计学习交流群 我们的目标 做啥的 怎么玩 我们的目标 Help you make good designs. 做啥的 本群以技术讨论为主,偶尔娱乐:要谈谈日常工作,生活也行 ...

  7. FPGA学习及设计中的注意事项

    为什么80%的码农都做不了架构师?>>>    FPGA学习及设计中的注意事项 1.基础问题 FPGA的基础就是数字电路和HDL语言,想学好FPGA的人,建议床头都有一本数字电路的书 ...

  8. 基于FPGA的数字识别实现

    前言 数字识别在我们生活中很常见,比如车牌识别.本篇博客就将介绍数字识别的方法,由于只是研究数字识别的方法,我们就不用硬件平台,而是用Modelsim和Matlab来仿真验证. 具体方法如下: 我们用 ...

  9. FPGA学习网站、开源网站和论坛网站汇总

    分享FPGA常用的一些学习网站.开源网站和论坛网站,方便大家找资料,查问题. 一.基础类学习网站 1.HDLbits(初学者入门) HDLBits有一系列的 Verilog 基础知识,可以在线仿真的学 ...

最新文章

  1. pycharm代码模板设置
  2. 新手安装ruby on rails(ror)的成功必备手册
  3. 11月17日学习内容整理:jquery文档处理,事件细讲,动画
  4. 比亚迪汉鸿蒙系统测评_深度:预判比亚迪汉EV电驱动系统技术状态
  5. English Through Movie
  6. 关于webapp的一点思考
  7. 【排序】动画演示10大排序算法
  8. The `certs(%1$s)` contains the merchant‘s certificate serial number(%2$s) which is not allowed here.
  9. c语言矩形法e3x x7,矩形法(梯形法)求定积分的方法
  10. Mysql 地区经纬度 查询
  11. free掉结点一定会造成断链吗?
  12. 数据库小技能:序列和伪列
  13. LeetCode 39 组合总和
  14. latex tips 偏导数符号 单词partial+倒三角 \nabla
  15. 如何用妙记多 Mojidoc 设置子弹笔记
  16. Ristretto 简介:一个高性能 GO 缓存
  17. 服务器2012还原系统,Windows Server 2012升级R2过程中意外关闭恢复原系统方法
  18. linux终端有颜色字体
  19. 《百年孤独》15句经典语录
  20. 计算机网络实验_三层架构企业网络_基于Cisco Packet Tracer模拟器

热门文章

  1. Laravel 报错 file_put_contents(): failed to open stream......解决
  2. 种草一个让程序员男友记住一辈子的神仙插件!
  3. matlab中for循环,while循环的基本使用。
  4. mysql数据库是的缩写_MYSQL数据库命名与其设计规范
  5. 大数据最重要的算法是什么,最常用的算法有哪些?
  6. [ Python ] 数据挖掘:股票价格
  7. 何制作手机自适应网页
  8. 【Matlab】用程序制作简单音乐
  9. 【毕业设计源码】基于Python的校园生活助手(二手+活动+论坛+新闻)信息系统
  10. 超能陆战队大白html代码,HTML加CSS技术打造超能陆战队的大白