数字系统课程设计——VHDL密码锁控制器

本文详细介绍了使用VHDL语言设计的密码锁控制器,该设计基于FPGA(Nexys4DDRArtix-7)和Vivado2018进行仿真和硬件调试。系统包括用户和管理员两种状态,具备输入密码、验证、报警、修改密码等功能,并对多时钟问题和数码管显示进行了优化解决。硬件测试验证了设计的正确性,如正确显示密码、错误提示及报警状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@数字系统课程设计

VHDL密码锁控制器

VHDL语言设计的密码锁控制器,模拟仿真平台为vivado 2018。(学生:慌慌和张张)
使用器材:Nexys4 DDR Artix-7 FPGA
设计软件:Vivado2018

设计要求

(1)设计一个4位密码锁,用户拨动相应的开关进入输入密码状态,输入4位密码,按下确定键后,若密码正确,锁打开,若密码错误,将提示密码错误,要求重新输入,三次输入都错误,将发出报警信号。
(2)用户输入密码时,在按下确定键之前,可以通过按退格键修正,每按一次退格键消除一位密码。
(3)报警后,只有管理员作相应的处理(专用按键)才能停止报警。
(4)管理员可以通过设置(专用按键)更改密码。
(5)如果没有预置密码,密码缺省为“0000”。
(6)正确开锁后,用户处理完毕后,按下确定键,系统回到等待状态。
(7)系统操作过程中,只要密码锁没有打开,如果10秒没有对系统操作,系统回到等待状态。
(8)系统操作过程中,如果密码锁已经打开,如果20秒没有对系统操作,系统自动上锁,回到等待状态。

功能描述

(1)用户密码初始值为“1234”;
(2)管理员密码初始值为“0000”;
(3)非报警状态下,只要密码锁没有打开,如果10秒没有对系统操作,系统回到等待状态。
(4)非报警状态下,密码锁已经打开,如果20秒没有对系统操作,系统回到等待状态
(5)操作分为用户状态和管理员状态
(6)等待状态默认为用户状态
用户状态
(1)设计一个4位密码锁,用户拨动相应开关进入输入密码状态,输入4位密码,通过数码管显示出来,按下确定键后,若密码正确,锁打开,数码管显示“HELLO”,若密码错误,数码管显示“ERROR”要求重新输入,三次输入都错误,将发出报警信号(10个LED灯闪烁)等待管理员操作。
(2)开锁后,用户可按相应键关锁,回到等待状态,也按下相应键进入修改密码状态,输入四位新密码,按下确认键则修改密码成功。
管理员状态
(1)报警状态下,管理员按下相应键进入输密码状态,输入四位管理员密码,按下确定键进行验证(错误则提示“ERROR”重新输入,没有次数限制)。
(2)验证通过后,管理员可以按下管理员键停止报警,也可以按相应键修改用户密码,输入4位密码后按确认键则修改密码成功。

设计思路

根据自顶向下的设计方法,先确定系统顶层实体的功能设计,按功能划分成若干模块,系统主要由6个模块构成,分别是控制模块,分频模块,显示模块,计数器模块,输入模块,编码模块,然后由6个模块实现具体功能。其中控制模块主要由状态机构成。然后先编写test_bench文件,在仿真平台上运行代码,然后再下载到FPGA板子中,进行硬件的调试。
状态图

state_pic
接口设置
状态机输入:共有16个按键输入,10个按键输入0~9,6个按键分别为重置,管理员键,用户键,改密码建,确定键,返回键;
状态机输出:16个LED灯,四位数码管输出。
时钟信号100MHz
状态描述
等待状态 S
等待输入第一位密码状态
等待输入第二位密码状态:S2
等待输入第三位密码状态:S3
等待输入第四位密码状态:S4
密码比较状态:S5
开锁状态:Sopen
管理员状态:Sadmin
报警状态:Salarm
错误状态:Serror

程序设计

密码锁显示模块:给七段数码管显示信号赋值

process(clk)
begin
case data is
when "0000"=>seg7<="10000001";              --数码管显示内容为0
when "0001"=>seg7<="11001111";              --数码管显示内容为1
when "0010"=>seg7<="10010010";              --数码管显示内容为2
when "0011"=>seg7<="10000110";             --数码管显示内容为3
when "0100"=>seg7<="11001100";             --数码管显示内容为4
when "0101"=>seg7<="10100100";            --数码管显示内容为5
when "0110"=>seg7<="10100000";              --数码管显示内容为6
when "0111"=>seg7<="10001111";              --数码管显示内容为7
when "1000"=>seg7<="10000000";               --数码管显示内容为8
when "1001"=>seg7<="10000101";               --数码管显示内容为9
when "1010"=>seg7<="11001000";               --数码管显示内容为H
when "1011"=>seg7<="10110000";             --数码管显示内容为E
When "1100"=>seg7<="11110001";             --数码管显示内容为L
when "1101"=>seg7<="10001000";             --数码管显示内容为R
When others =>seg7<="11111110";             --数码管显示内容为-
end case;
end process;

给数码管引脚赋值,进行显示

   process(clk_in1)                                                                --数码管显示模块,固定显示4位密码
   variable n,m,x:std_logic_vector(2 downto 0):="000";
   begin
    if(clk_in1'event and clk_in1= '1') then   --1khz的时钟信号触发,无法改变
      if (state = sopen) then                                                      --显示开锁信号
               case m is
               when "000"=> segselect8<="01111111";data<="1010";                      --显示H
               when "001" =>segselect8<="10111111";data<="1011";                    --显示E
               when "010" =>segselect8<="11011111";data<="1100";                   --显示L
               when "011" =>segselect8<="11101111";data<="1100";                    --显示L
               when "100" =>segselect8<="11110111";data<="0000";                    --显示O
               when others =>segselect8<="11111111";data<="1111";
               end case;     
               m := m+1;
               if(m="101") then
                  m:="000";
               end if;                                                                    --显示错误
       elsif (state = serror or state = salarming)then
                case x is
when "000"=> segselect8<="01111111";data<="1011";                      --显示E
when "001" =>segselect8<="10111111";data<="1101";                    --显示R
when "010" =>segselect8<="11011111";data<="1101";                   --显示R
when "011" =>segselect8<="11101111";data<="0000";                    --显示O
when "100" =>segselect8<="11110111";data<="1101";                    --显示R
when others =>segselect8<="11111111";data<="1111";
end case;
x := x+1;
If(x="101") then
x:="000";
end if;                                                                  --显示开锁信号
      else
             case n is
when "000"=> segselect8<="01111111";data<=code3;                      --显示第一位密码
when "001" =>segselect8<="10111111";data<=code2;                    --显示第二位密码
when "010" =>segselect8<="11011111";data<=code1;                   --显示第三位密码
when "011" =>segselect8<="11101111";data<=code0;                    --显示第四位密码
when others =>segselect8<="11111111";data<="1111";
end case;
n := n+1;
if(n="100") then
n:="000";
              end if;
        end if;
   end if;
   end process;

密码锁分频计数模块
时钟分频信号2,产生1000HZ的时钟信号,用于数码管的显示

PROCESS(clk)                                  
Variable count:integer range 0 to 100000;      --
BEGIN
   IF (clk'event AND clk='1') THEN   --时钟上升沿
         IF(count<=49999) THEN
             clk_in1<='1';  
             count := count +1;
         elsif(count=100000) then
              count:=0;
         else
            count := count +1;
            clk_in1<= '0';
         End if;
   End if;
End process;                                      --时钟分频信号验证成功

系统仿真波形

输入初始密码“1234”,从上述波形可以看到yonghumima代表正确用户密码,out_code代表输入的密码,这里可以看到密码输入成功,密码锁打开。
在这里插入图片描述
修改输入密码,首先输入初始密码“1234”,开锁后按下改密码键,将密码修改为“2345”;可以看到yonghumima用户密码从“1234”变为“2345”,表示修改密码成功。
Data[3~0]代表输入的4位密码,从图中也可以看到每次输入的密码。
仿真波形为:
在这里插入图片描述

硬件测试

正确输入密码“1234”,数码管显示:
在这里插入图片描述
按下确定键,验证密码正确,数码显示“HELLO”表示开锁成功。
在这里插入图片描述
密码输入错误,数码管显示“ERROR”提示输入密码错误:
在这里插入图片描述
三次密码输入错误,10个LED灯闪烁报警:
在这里插入图片描述

分析与总结

1.多时钟问题
在写代码过程,在控制模块的进程使用了多个时钟信号来满足不同的功能,例子如下:在主进程中同时使用了判断条件(clk’event and clk = ‘1’)和(back’EVENT and back=‘1’),逻辑上并无错误,仿真也可以正常进行,并无错误,但是在综合布线时报错,
解决方案
经查证,这个错误主要是由于一个process不可以由两个时钟触发,会产生竞争冒险,综合时会报错,因此可以给clk以外的时钟信号,增加一级状态,利用信号的值在进程结束以后才会更新的特点,利用寄存器来判断信号是否出现上升沿,例如(back’EVENT and back=‘1’)可以改写为
Process(clk)
Begin
If(clk’event and clk = ‘1’) then
Myback<=back;
If(Myback = ‘0’and back = ‘1’) then
……
End if;
End if;
这样就可以将back上升沿的判定改写为(Myback = ‘0’and back = ‘1’)。
2.数码管的显示问题
由于共阳极数码管每次只能点亮一个,因此需要将数码管按一定的频率依次点亮,利用视觉停留效果实现多个数码管的点亮,但是在实验中发现如果使用100Mhz的频率点亮数码管,数码管的显示会出现极大地错误,并不能显示相应的数字,而是会出现以下的效果,数码管出现混叠的状况,无法正常显示。
在这里插入图片描述
分工
程序与仿真:慌慌,张张
硬件调试:慌慌,张张
实验报告:慌慌,张张

完整工程代码和实验报告:https://download.csdn.net/download/qq_41663196/20429906?spm=1001.2014.3001.5501

### 解析 Import Error 的常见原因 当遇到 `ImportError: cannot import name 'Generic'` 错误时,通常意味着尝试从模块中导入的对象不存在或无法访问。此问题可能由多种因素引起: - 版本不兼容:不同库之间的版本冲突可能导致此类错误。 - 安装缺失:目标库未正确安装或路径配置有误。 - 导入语句不当:可能存在循环依赖或其他语法层面的问题。 ### 针对 Generic 类型的具体解决方案 对于特定于 `Generic` 的情况,考虑到 Python 中 `Generic` 是 typing 模块的一部分,在处理该类别的 ImportError 时可采取如下措施[^1]: #### 方法一:确认typing模块可用性 确保环境中已安装标准库中的 typing 模块,并且其版本支持所使用的特性。可以通过以下命令验证: ```bash python -c "from typing import Generic; print(Generic)" ``` 如果上述命令执行失败,则可能是由于 Python 或者相关扩展包的版本过低造成的。此时应考虑升级至更高版本的解释器以及对应的开发工具链。 #### 方法二:调整导入方式 有时直接通过顶层命名空间来获取所需组件会更稳定可靠。修改代码以采用这种做法可能会解决问题: ```python from collections.abc import Iterable # 如果是迭代器相关接口 from typing import TypeVar, Protocol # 对于协议和泛型定义 T = TypeVar('T') class MyContainer(Protocol[T]): ... ``` 注意这里并没有显式提到 `Generic` ,而是利用了更为基础的数据结构抽象基类或是其他替代方案实现相同功能[^2]。 #### 方法三:排查环境变量设置 检查系统的 PYTHONPATH 和虚拟环境配置是否正常工作。任何异常都可能导致某些第三方软件包找不到必要的资源文件而引发类似的错误提示。建议清理并重建项目专属的工作区以便排除干扰项的影响。 #### 示例修正后的代码片段 假设原始代码试图这样引入 `Generic` : ```python from some_module import Generic # 可能导致 ImportError ``` 改为遵循官方文档推荐的方式后变为: ```python from typing import Generic # 正确的做法 ```
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值