前言
作者目前(2023年12月)是一名计算机大三学生,该课程设计是我半年前写的,发出来供大家参考。由于VHDL在之后的学习中用的不多,所以不帮忙做数字密码锁外的其他需求。数字逻辑是我觉得最有意思的一门课,希望大家可以根据我给的框架独立完成,对数字密码锁设计有疑问或需求的话可以私信我(留下联系方式,备注来意,急的话加我小号QQ 1242484192),大家加油。
2024年6月25日补充:项目已开源,要下载完整资源的移步至https://download.csdn.net/download/systemcall0122/89481456?spm=1001.2014.3001.5503
一、课程设计目的
1、学会应用数字系统设计方法进行数字电路设计;
2、进一步提高quartus II软件的开发应用能力;
3、提高VHDL进行综合设计的能力;
4、培养学生书写综合实验报告的能力。
二、课程设计内容
根据所选题目列出具体内容要求
1、密码锁采用十进制数形式,可以进行密码修改,错误报警等功能。
2、如果输入的密码与设置的密码相同,则密码锁被打开,控制器的输出端key=0;否则控制输出端warn=1,发出警报。
3、实验时,“上锁”状态通过发光的LED灯显示,声、光报警通过有源蜂鸣器和LED灯指示
4、写出设计步骤,对各个模块设计VHDL代码
5、画出电路原理图
6、对设计的电路进行仿真、修改,使仿真结果达到设计要求。
三、实验方案分析与设计
根据“自顶向下”的设计方法,先确定系统顶层实体的功能设计,按功能划分为若干模块,然后对每一个模块进一步细分,得到简单易实现的子模块。
经分析,该数字密码锁有如下模块:控制器、用于记录输入密码位数的计数器1、用于记录错误次数的计数器2、比较器、译码器、寄存器。
控制器本质上为一个具有7个状态的状态机,由各转移信号控制以进入对应的状态。具体状态有:OUTLOCK(开锁)、INLOCK(关锁)、PS_INPUT(输入密码)、PS_CHANGE(修改密码)、PS_RIGHT(密码正确)、PS_WRONG(密码错误)、ALARM(警报)。
(下面几个模块写得简略一点)
译码器:将输入信号转为二进制
比较器:比较译码器输出信号是否与寄存器中预设密码相同
计数器1:记录密码输入位数
计数器2:记录错误次数
寄存器:根据使能信号的不同实现不同功能,修改密码 / 传输密码
四、具体实现过程描述
(VHDL的层次化是相当显著的,这边我给大家一个顶层封装逻辑图和一个重要模块的底层代码设计)
注意:只是供大家参考,根据每个人设计的不同,每个模块会有不同的端口。
顶层封装逻辑图:
下面给出最重要的控制器的底层逻辑,给出了两个状态对应的逻辑信号控制和状态转移控制。如果读者理解了数字密码锁的要求(什么状态读什么信号转移成什么状态)和上面的顶层封装逻辑图的话,仿照给出模块将控制器代码补全并不是难事。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
entity control1 is
port(
clk:in std_logic; --时钟信号
lock:in std_logic; --上锁信号
start:in std_logic; --开始输入密码信号
off_al:in std_logic; --消除警报信号
ps_ch:in std_logic; --修改密码信号
enter:in std_logic; --确认信号
wro_count:in std_logic; --错误次数
ps_i:in std_logic; --输入密码
cmp_r:in std_logic; --比较器结果
cin:in std_logic; --密码位数是否正确
code_en:out std_logic; --译码器使能
cnt_clr:out std_logic; --计数器1清零
cnt_clr2:out std_logic; --计数器2清零
cnt_clk2:out std_logic; --计数器2时钟
reg_wr:out std_logic; --决定寄存器当前作用是输出密码还是修改密码
key:out std_logic; --锁的开关
warn:out std_logic --警报信号
);
end control1;
architecture behave of control1 is
CONSTANT KEY_ACTIVE:STD_LOGIC:='1'; --有效电平
type state_type is (OUTLOCK,INLOCK,PS_INPUT,PS_RIGHT,PS_WRONG,ALARM,PS_CHANGE); --七个状态
signal state:state_type;
begin
process(clk)
begin
if rising_edge(clk) then
case state is
--------------------------
when OUTLOCK=> --开锁状态
key<='0';
--状态转移
if lock=KEY_ACTIVE then
state<=INLOCK;
ELSIF ps_ch=KEY_ACTIVE then
state<=PS_CHANGE;
ELSE
state<=OUTLOCK;
end if;
--------------------------
when INLOCK=> --关锁状态
--控制其他模块的信号
--状态转移
-------------------------
when PS_INPUT=> --输入密码状态
--控制其他模块的信号
key<='1';
code_en<='1';
cnt_clr<='0';
reg_wr<='0';
--状态转移
if cin='1' and ps_i='1' and cmp_r='1' then
code_en<='0';
cnt_clr<='1';
cnt_clr2<='1';
state<=PS_RIGHT;
elsif ps_i='1' and cmp_r='0' then
code_en<='0';
cnt_clr<='1';
cnt_clr2<='0';
cnt_clk2<='1';
state<=PS_WRONG;
elsif enter=KEY_ACTIVE and cin='0' then
code_en<='0';
cnt_clr<='1';
cnt_clr2<='0';
cnt_clk2<='1';
state<=ALARM;
else
state<=PS_INPUT;
end if;
--------------------------
when PS_RIGHT=> --密码正确
--状态转移
-------------------------
when PS_WRONG=> --密码错误
--状态转移
-------------------------
when ALARM=> --警报状态
--状态转移
-------------------------
when PS_CHANGE=> --修改密码状态
--控制其他模块的信号
--状态转移
-------------------------
WHEN OTHERS=>
state<=INLOCK;
end case;
end if;
end process;
end behave;
至于其他功能模块……把控制器补全之后其他模块也并不难,译码器、计数器、比较器都是非常经典的应用,但寄存器需要动点脑筋(因为我的寄存器根据使能信号有两个功能,所以当时花了点时间想办法,不想想办法的话把寄存器拆成两个模块也可以)
总的来说,数字逻辑课程的逻辑性是非常强的,用低级语言去完成一个逻辑性极强的设计确实有一定难度,需要大家好好思考。
数字密码锁设计的所有文件:
五、实现效果
系统上电时,处于开锁状态(OUTLOCK),此时默认密码为“0000”。当输入ps_ch信号时,系统进入修改密码状态(PS_CHANGE);若输入lock信号,进入关锁状态(INLOCK),锁闭合;在关锁状态,输入start信号,进入密码输入状态(PS_INPUT);在输入密码状态,由ps_i密码脉冲作为计数时钟,计数值输出作为寄存器地址,当计数器计到4时,返回计数满信号cin,如果密码内容和长度均正确,进入密码初验正确状态(PS_RIGHT),如果密码错误,进入密码初验错误状态(PS_WRONG);在密码初验错误状态,输入确认信号enter时,进入开锁状态;在密码初验错误状态,输入确认信号enter时,如果错误次数没有达到4次,则进入关锁状态并输出错误信号,如果错误次数达到4次,进入报警状态;在报警状态, warn信号等于‘1’,如果输入清除警报信号off_al,进入关锁状态。
六、总结
本次课程设计中遇到了很多有意思的问题,我也针对这些问题想出了许多解决方法。比如说,怎么去输入密码。一开始的想法是用四个译码器去编译每一个输入的数据,然后将这些数据并行输入到比较器中,但这样的化又需要另外需要四个译码器去设置密码,从实际考虑需要消耗非常多的材料。况且如果要修改密码位数的话又需要在原理图中修改译码器的个数,非常麻烦。经过思考,我通过一个addr信号去控制了密码输入的位数,也通过这个信号控制了当前输入的数是第几位,如果需要改变密码位数的话也只要在代码里修改addr的取值范围就好;通过一个寄存器完成了修改密码与输入密码两个功能,将预置密码与输入密码需要的译码器合并为一个,极大地节省了材料。而且如果不使用状态机的话,各种功能之间的转换需要非常非常多的元件模块,工程量大又要耗费许多材料。
因此,从上述经历中我得到的最大的启发就是:在实际行动之前,一定要对将要完成的任务做充分的思考,从而找到一个更好的解决方案。那些简单粗暴的方法(比如在本次课程设计中使用八个译码器,不使用状态机而去直接连接各个时序电路等等)可以让我们很快地开始着手制作,但最后的结果往往不尽如人意。只有经过充分的考量,才可以得出一个较为完美的解决方案。