FPGA学习——数字密码锁(下)
数字密码锁(下)
上篇整理了前两个模块,可以做出来功能按键以及数字按键的信号,接着就要利用这些信号对密码锁进行控制。
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学习——数字密码锁(下)相关推荐
- FPGA学习——数字密码锁(上)
基于FPGA的数字密码锁 一.简介 1.1设备要求 1.2 功能要求 二.工程分析: 三.具体程序: 顶层模块: 1.矩阵键盘扫描模块 2.功能划分模块 第三.第四模块在下篇中 四.总结: 一.简介 ...
- 基于FPGA的数字密码锁电路设计(含程序)
录 题目 设计思路 代码设计 题目 (1)4个按键分别设置4位数码管上的显示数字,当按键设置的数字与设置的4位密码一致时,蜂鸣器响,表示锁打开: (2)具备通过按键手动修改数字密码的功能: (3)具备 ...
- FPGA学习之 直接数字频率合成器(DDS)
目录 FPGA学习之 直接数字频率合成器(DDS) FPGA学习之 直接数字频率合成器(DDS) DDS的原理: 直接数字频率合成器(Direct Digital Synthesizer, DDS)是 ...
- FPGA学习之 状态机实现数码管的数字时钟
FPGA学习之 状态机实现数字时钟 开发板型号:EP4CE6F17C8 六位数码管原理图: 由图可知,数码管段选和片选均为低电平有效. 由于人眼的视觉残留,我们控制一定频率对每一位数码管进行刷新,就能 ...
- 基于FPGA的数字视频信号处理器设计(下)
基于FPGA的数字视频信号处理器设计(下) 今天给大侠带来基于FPGA的数字视频信号处理器设计,由于篇幅较长,分三篇.今天带来第三篇,下篇,程序测试与运行.话不多说,上货. 导读 图像是用各种观测系统 ...
- FPGA设计/数字IC前端设计学习交流群
FPGA设计/数字IC前端设计学习交流群 我们的目标 做啥的 怎么玩 我们的目标 Help you make good designs. 做啥的 本群以技术讨论为主,偶尔娱乐:要谈谈日常工作,生活也行 ...
- FPGA学习及设计中的注意事项
为什么80%的码农都做不了架构师?>>> FPGA学习及设计中的注意事项 1.基础问题 FPGA的基础就是数字电路和HDL语言,想学好FPGA的人,建议床头都有一本数字电路的书 ...
- 基于FPGA的数字识别实现
前言 数字识别在我们生活中很常见,比如车牌识别.本篇博客就将介绍数字识别的方法,由于只是研究数字识别的方法,我们就不用硬件平台,而是用Modelsim和Matlab来仿真验证. 具体方法如下: 我们用 ...
- FPGA学习网站、开源网站和论坛网站汇总
分享FPGA常用的一些学习网站.开源网站和论坛网站,方便大家找资料,查问题. 一.基础类学习网站 1.HDLbits(初学者入门) HDLBits有一系列的 Verilog 基础知识,可以在线仿真的学 ...
最新文章
- pycharm代码模板设置
- 新手安装ruby on rails(ror)的成功必备手册
- 11月17日学习内容整理:jquery文档处理,事件细讲,动画
- 比亚迪汉鸿蒙系统测评_深度:预判比亚迪汉EV电驱动系统技术状态
- English Through Movie
- 关于webapp的一点思考
- 【排序】动画演示10大排序算法
- The `certs(%1$s)` contains the merchant‘s certificate serial number(%2$s) which is not allowed here.
- c语言矩形法e3x x7,矩形法(梯形法)求定积分的方法
- Mysql 地区经纬度 查询
- free掉结点一定会造成断链吗?
- 数据库小技能:序列和伪列
- LeetCode 39 组合总和
- latex tips 偏导数符号 单词partial+倒三角 \nabla
- 如何用妙记多 Mojidoc 设置子弹笔记
- Ristretto 简介:一个高性能 GO 缓存
- 服务器2012还原系统,Windows Server 2012升级R2过程中意外关闭恢复原系统方法
- linux终端有颜色字体
- 《百年孤独》15句经典语录
- 计算机网络实验_三层架构企业网络_基于Cisco Packet Tracer模拟器
热门文章
- Laravel 报错 file_put_contents(): failed to open stream......解决
- 种草一个让程序员男友记住一辈子的神仙插件!
- matlab中for循环,while循环的基本使用。
- mysql数据库是的缩写_MYSQL数据库命名与其设计规范
- 大数据最重要的算法是什么,最常用的算法有哪些?
- [ Python ] 数据挖掘:股票价格
- 何制作手机自适应网页
- 【Matlab】用程序制作简单音乐
- 【毕业设计源码】基于Python的校园生活助手(二手+活动+论坛+新闻)信息系统
- 超能陆战队大白html代码,HTML加CSS技术打造超能陆战队的大白