2024年2月11日发(作者:)

数字电路设计实验报告

学院:

班级:

学号:

姓名:

——简易密码锁

目录

 任务要求

 系统设计

 设计思路

 总体框图

分块设计

 波形仿真及波形分析

 源代码

 功能分析

 故障分析及问题解决

 总结及结论

 任务要求

设计并实现一个数字密码锁,密码锁有四位数字密码和一个确认开锁按键,密码输入正确,密码锁打开,密码输入错误进行警示。

基本要求:

1、密码设置:通过键盘进行4 位数字密码设定输入,在数码管上显示所输入数字。通过密码设置确定键(BTN 键)进行锁定。

2、开锁:在闭锁状态下,可以输入密码开锁,且每输入一位密码,在数码管上显示“-”,提示已输入密码的位数。输入四位核对密码后,按“开锁”键,若密码正确则系统

开锁,若密码错误系统仍然处于闭锁状态,并用蜂鸣器或led 闪烁报警。

3、在开锁状态下,可以通过密码复位键(BTN 键)来清除密码,恢复初始密码“0000”。

闭锁状态下不能清除密码。

4、用点阵显示开锁和闭锁状态。

提高要求:

1、输入密码数字由右向左依次显示,即:每输入一数字显示在最右边的数码管上,同时将先前输入的所有数字向左移动一位。

2、密码锁的密码位数(4~6 位)可调。

3、自拟其它功能。

 系统设计

 设计思路

将电子密码锁系统分为三个部分来进行设计,数字密码输入部分、密码锁控制电路和密码锁显示电路。密码锁输入电路包括时序产生电路,键盘扫描电路,键盘译码电路等,将用

户手动输入的相关密码信息转换为软件所能识别的编码,作为整个电路的输入。密码锁控制电路包括相应的数据存储电路,密码核对电路,能够进行数值的比较,进行电路解锁,开锁,密码的重新设置等。密码锁显示电路包括将待显示数据的BCD码转换成数码管的七段显示驱动编码,密码锁在相应的状态下的点阵输出以及蜂鸣器的报警输出。

 总体框图

密码锁显示电路

密码锁控制电路

数码管显示

按确认键

键入状态

按确认键

按复位键

键入初始密码0000

密码正确

开锁状态

报警电路

密码更改与密码设计电路

密码错误

闭锁状态

按复位键

报警状态

分块设计

 键盘扫描电路

首先,向列扫描地址逐列输出低电平,然后从行码地址读回,如果有键摁下,则相应行的值应为低,如果没有按键按下,由于上拉的作用,行码为高。这样就可以通过输出列码和读取的行码来判断按下的是什么键。在判断有按键的按下后,要有一定的延时,防止键盘抖动。

entity keyboard is

port(

row:in std_logic_vector(3 downto 0);

col:out std_logic_vector(3 downto 0);

keyout:out std_logic_vector(3 downto 0);

q:out std_logic;

clk:in std_logic

);

end keyboard;

architecture struct of keyboard is

signal col_buffer1:std_logic_vector(3 downto 0);

signal col_buffer2:std_logic_vector(3 downto 0);

signal key :std_logic_vector(7 downto 0);

signal counter:integer range 0 to 3;

signal delay:integer range 0 to 10;

signal stop:std_logic;

begin

col <= col_buffer2;

q <= stop;

process(CLK,row,stop)

begin

if clk'event and clk = '1' then

if counter = 3 then

counter <= 0;

else

counter <= counter + 1;//由于只要求输入四个数字所以需要计数

end if;

case counter is

when 0 => col_buffer1 <= "1110";

when 1 => col_buffer1 <= "1101";

when 2 => col_buffer1 <= "1011";

when 3 => col_buffer1 <= "0111";

end case;

end if;

end process;

key <= row & col_buffer2;

process(clk,key)

begin

if clk'event and clk = '0' then

case key is

when "01111110" => stop<='1';keyout<="0000";

when "01111101" => stop<='1';keyout<="0001";

when "01111011" => stop<='1';keyout<="0010";

when "01110111" => stop<='1';keyout<="0011";

when "10111110" => stop<='1';keyout<="0100";

when "10111101" => stop<='1';keyout<="0101";

when "10111011" => stop<='1';keyout<="0110";

when "10110111" => stop<='1';keyout<="0111";

when "11011110" => stop<='1';keyout<="1000";

when "11011101" => stop<='1';keyout<="1001";

when others => stop <= '0';//仅仅在摁0~9的时候会有显示,在摁除了这十个键之外的键的时候是不会有反应的,将keyout的值转换为相应的数码管值,来控制数码管的显示

end case ;

end if;

end process;

process(clk,stop)

begin

if clk'event and clk = '1'then

if stop = '0' then

col_buffer2 <= col_buffer1;

end if;

end if;

end process;

end struct;

 点阵显示电路

采用行扫描的方式,每经过一段时间,给一行一个低电平。则若在列的方向上如果接入高电平,则会使相应的二极管发光。由于人眼的的暂留效应就回使我们看到我们想要的图案。

library ieee;

use _logic_;

entity led is

port(

row:out std_logic_vector(7 downto 0);

num:in std_logic_vector(1 downto 0);

clk:in std_logic;

col:out std_logic_vector(7 downto 0)

);

end entity;

architecture struct of led is

signal counter : integer range 0 to 7;

begin

process(clk)

begin

if clk'event and clk = '1' then

if counter = 7 then

counter <= 0;

else

counter <= counter +1;

end if;

end if;

end process;

process(clk,counter)

begin

if clk'event and clk = '0' then

if num <= "00" then//键入状态

case counter is

when 0 => row <= "11111110"; col <= "00111100";

when 1 => row <= "11111101"; col <= "00111100";

when 2 => row <= "11111011"; col <= "00111100";

when 3 => row <= "11110111"; col <= "00111100";

when 4 => row <= "11101111"; col <= "00111100";

when 5 => row <= "11011111"; col <= "00011000";

when 6 => row <= "10111111"; col <= "00111100";

when 7 => row <= "01111111"; col <= "00011000";

end case;

elsif num = "01" then//闭锁状态

case counter is

when 0 => row <= "11111110"; col <= "11111111";

when 1 => row <= "11111101"; col <= "11111111";

when 2 => row <= "11111011"; col <= "11111111";

when 3 => row <= "11110111"; col <= "11111111";

when 4 => row <= "11101111"; col <= "01000010";

when 5 => row <= "11011111"; col <= "01000010";

when 6 => row <= "10111111"; col <= "01000010";

when 7 => row <= "01111111"; col <= "00111100";

end case;

elsif num = "10" then//开锁状态

case counter is

when 0 => row <= "11111110"; col <= "00000000";

when 1 => row <= "11111101"; col <= "00011111";

when 2 => row <= "11111011"; col <= "00011111";

when 3 => row <= "11110111"; col <= "00011111";

when 4 => row <= "11101111"; col <= "10011111";

when 5 => row <= "11011111"; col <= "10001000";

when 6 => row <= "10111111"; col <= "10001000";

when 7 => row <= "01111111"; col <= "01110000";

end case;

else

case counter is//报警状态

when 0 => row <= "11111110"; col <= "00011000";

when 1 => row <= "11111101"; col <= "00111100";

when 2 => row <= "11111011"; col <= "00011000";

when 3 => row <= "11110111"; col <= "00011000";

when 4 => row <= "11101111"; col <= "00111100";

when 5 => row <= "11011111"; col <= "00111100";

when 6 => row <= "10111111"; col <= "00111100";

when 7 => row <= "01111111"; col <= "00011000";

end case;

end if;

end if;

end process;

end struct;

 数码管显示

其中引脚图的两个COM端连在一起,是公共端,共阴数码管要将其接地,共阳数码管将其接正5伏电源。一个八段数码管称为一位,多个数码管并列在一起可构成多位数码管,它们的段选线(即a,b,c,d,e,f,g,dp)连在一起,而各自的公共端称为位选线。显示时,都从段选线送入字符编码,而选中哪个位选线,那个数码管便会被点亮。数码管的8段,对应一个字节的8位,a对应最低位,dp对应最高位。所以如果想让数码管显示数字0,那么共阴数码管的字符编码为00111111;共阳数码管的字符编码为11000000。

process(clk,counter)

begin

if clk'event and clk = '0' then

case counter is//选通,可使数码管只单独亮一位

when 0 => cat <= "111110";ao<=a0;

when 1 => cat <= "111101";ao<=a1;

when 2 => cat <= "111011";ao<=a2;

when 3 => cat <= "110111";ao<=a3;

when 4 => cat <= "101111";ao<=a4;

when 5 => cat <= "011111";ao<=a5;

end case;

end if;

end process;

process(ao)

begin

case ao is//将键盘输入的一系列值翻译成接通数码管值

when "0000" => a<="1111110";

when "0001" => a<="0110000";

when "0010" => a<="1101101";

when "0011" => a<="1111001";

when "0100" => a<="0110011";

when "0101" => a<="1011011";

when "0110" => a<="1011111";

when "0111" => a<="1110000";

when "1000" => a<="1111111";

when "1001" => a<="1111011";

when "1010" => a<="0000001";

when others => a<="0000000";

end case ;

end process;

end struct;

 仿真波形及波形分析

如图,程序开始运行的时候,给键盘扫描,系统会给出相应的键盘输出,是点阵显示出输入状态

图为一系列当键盘键入的时候,一系列数码管显示

在键入改变的初始密码之后,系统会变成闭锁状态,点阵如图显示

当输入的密码错误的时候,摁清零键的时候,会发出警报

 源代码

library ieee;

use _logic_;

entity lock is

port(

----key

----led

----seg

clk:in std_logic;//时钟信号

rr:in std_logic;//重置清零键

s:in std_logic;//确认键

warn:out std_logic;//警报信号

ou:out std_logic_vector(3 downto 0);

key_row:in std_logic_vector(3 downto 0);//键盘扫描行列

key_col:out std_logic_vector(3 downto 0);

led_col:out std_logic_vector(7 downto 0);//点阵扫描行列

led_row:out std_logic_vector(7 downto 0);

cat:out std_logic_vector(5 downto 0);//数码管选通

a:out std_logic_vector(6 downto 0)//数码管显示

);

end entity;

architecture struct of lock is

signal keynum:integer range 0 to 9;

signal warn_on:std_logic;

signal status:integer range 0 to 3;

signal num_counter:integer range 0 to 5;

signal clk_1000:std_logic;

signal clk_1:std_logic;

signal q:std_logic;

signal r:std_logic;

signal w:std_logic;

signal num:std_logic_vector(1 downto 0);

signal key:std_logic_vector(3 downto 0);

signal input:std_logic_vector(3 downto 0);

signal seg_num:std_logic_vector(2 downto 0);

signal p1,p2,p3,p4:std_logic_vector(3 downto 0);

signal password:std_logic_vector(15 downto 0);

signal delay:integer range 0 to 31;

component div is//分频器

port(

clk_in:in std_logic;

clk_1000:out std_logic;

clk_1:out std_logic

);

end component;

component keyboard is//键盘扫描

port(

row:in std_logic_vector(3 downto 0);

col:out std_logic_vector(3 downto 0);

keyout:out std_logic_vector(3 downto 0);

q:out std_logic;

clk:in std_logic

);

end component;

component led is//点阵显示

port(

row:out std_logic_vector(7 downto 0);

num:in std_logic_vector(1 downto 0);

clk:in std_logic;

col:out std_logic_vector(7 downto 0)

);

end component;

component seg is//数码管

port(

r:in std_logic;

clk:in std_logic;

cat:out std_logic_vector(5 downto 0);

a:out std_logic_vector(6 downto 0);

w:in std_logic;

input:in std_logic_vector(3 downto 0);

num:in std_logic_vector(2 downto 0)

);

end component;

component One is

port(

clk:in std_logic;

i:in std_logic;

o:out std_logic

);

end component;

begin

IC1:div port map(clk,clk_1000,clk_1);

IC2:keyboard port map(key_row,key_col,key,q,clk_1000);

IC3:led port map(row=>led_row,num=>num,clk=>clk_1000,col=>led_col);

IC4:seg port map(r=>r,clk=>clk_1000,cat=>cat,a=>a,w=>w,input=>input,num=>seg_num);

--status

process(s,rr,status)

begin

if rr = '1' then

if status = 2 then

status <= 0;

elsif status = 3 then

status <= 1;

end if;

elsif s'event and s = '1' then

if status = 0 then

status <= 1;

password <= p1&p2&p3&p4;

elsif status = 1 then

if password = p1&p2&p3&p4 then

status <= 2;

else

status <= 3;

end if;

else

status <= 1;

end if;

end if;

end process;

//statue 0代表的是输入状态,statue 1是闭锁状态,statue 2 是开锁状态,statue 3 是报警状态,状态转移图在前面已经画出

process(s,rr,clk_1000)

begin

if rr = '1' then

r <= '1';

elsif s = '1' then

r <= '1';

elsif clk_1000'event and clk_1000 = '0' then

r <= '0';

end if;

end process;

---num_counter

process(s,rr,q,clk_1000)

begin

if s = '1' then

num_counter <= 0;

elsif rr = '1' then

num_counter <= 0;

elsif q'event and q = '0' then

if status = 0 or status = 1 then

if num_counter < 4 then

num_counter <= num_counter+1;

else

num_counter <= 0;

end if;

end if;

end if;

end process;

//记录数据,只有在键入状态和闭锁状态的时候才能够输入密码,当输入超过四位数的时候,不予计数

--delay

process(clk_1000,q,status)

begin

if q = '1' then

if delay = 31 then

if status = 0 or status = 1 then

w <= '1';

end if;

else

delay <= delay +1;

end if;

elsif clk_1000'event and clk_1000 = '1' then

delay <= 0;

w <='0';

end if;

end process;

//需要有1k的时钟信号使得后面的数码管运行

--seg_num,input

process(clk,key)

begin

if clk'event and clk = '0' then

case num_counter is

when 0 => seg_num <= "101";p1 <= key;

when 1 => seg_num <= "100";p2 <= key;

when 2 => seg_num <= "011";p3 <= key;

when 3 => seg_num <= "010";p4 <= key;

when others => NULL;

//键入四位密码

end case;

if status = 0 then

input <= key;

elsif status = 1 then

input <= "1010";

else

input <= "1111";

end if;

end if;

//当在键入状态的时候,键入的密码会被记录在input里

end process;

--warn

process(clk_1,warn_on)

begin

if warn_on = '1' then

warn <= clk_1;

else

warn <= '0';

end if;

end process;

//报警系统的实现

--led and warn'led

process(clk)

begin

if clk'event and clk = '1' then

case status is

when 0 =>num <= "00";warn_on <= '0';

when 1 =>num <= "01";warn_on <= '0';

when 2 =>num <= "10";warn_on <= '0';

when 3 =>num <= "11";warn_on <= '1';

end case ;

end if;

end process;

//仅仅在报警状态的时候实现报警,否则不会报警

end struct;

library ieee;

use _logic_;

entity div is

port(

clk_in:in std_logic;

clk_1000:out std_logic;

clk_1:out std_logic

);

end entity;

//分频器的定义

architecture struct of div is

signal counter_1000:integer range 0 to 24999;

signal counter_1:integer range 0 to 24999999;

begin

process(clk_in)

begin

if clk_in'event and clk_in ='1' then

if counter_1000 = 24999 then

counter_1000 <= 0;

clk_1000 <= '1';

elsif counter_1000 = 12500 then

counter_1000 <= counter_1000 +1;

clk_1000 <= '0';

else

counter_1000 <= counter_1000 + 1;

end if;

end if;

end process;

process(clk_in)

begin

if clk_in'event and clk_in ='1' then

if counter_1 = 24999999 then

counter_1 <= 0;

clk_1 <= '1';

elsif counter_1 = 12500000 then

counter_1 <= counter_1 + 1;

clk_1 <= '0';

else

counter_1 <= counter_1 + 1;

end if;

end if;

end process;

end struct;

library ieee;

use _logic_;

//扫描键盘的程序

entity keyboard is

port(

row:in std_logic_vector(3 downto 0);

col:out std_logic_vector(3 downto 0);

keyout:out std_logic_vector(3 downto 0);

q:out std_logic;

clk:in std_logic

);

end keyboard;

architecture struct of keyboard is

signal col_buffer1:std_logic_vector(3 downto 0);

signal col_buffer2:std_logic_vector(3 downto 0);

signal key :std_logic_vector(7 downto 0);

signal counter:integer range 0 to 3;

signal delay:integer range 0 to 10;

signal stop:std_logic;

begin

col <= col_buffer2;

q <= stop;

process(CLK,row,stop)

begin

if clk'event and clk = '1' then

if counter = 3 then

end struct;

counter <= 0;

else

counter <= counter + 1;

end if;

case counter is

when 0 => col_buffer1 <= "1110";

when 1 => col_buffer1 <= "1101";

when 2 => col_buffer1 <= "1011";

when 3 => col_buffer1 <= "0111";

end case;

end if;

end process;

key <= row & col_buffer2;

process(clk,key)

begin

if clk'event and clk = '0' then

case key is

when "01111110" => stop<='1';keyout<="0000";

when "01111101" => stop<='1';keyout<="0001";

when "01111011" => stop<='1';keyout<="0010";

when "01110111" => stop<='1';keyout<="0011";

when "10111110" => stop<='1';keyout<="0100";

when "10111101" => stop<='1';keyout<="0101";

when "10111011" => stop<='1';keyout<="0110";

when "10110111" => stop<='1';keyout<="0111";

when "11011110" => stop<='1';keyout<="1000";

when "11011101" => stop<='1';keyout<="1001";

when others => stop <= '0';

end case ;

end if;

end process;

process(clk,stop)

begin

if clk'event and clk = '1'then

if stop = '0' then

col_buffer2 <= col_buffer1;

end if;

end if;

end process;

//点阵扫描及相应状态下的点阵输出

library ieee;

use _logic_;

entity led is

port(

row:out std_logic_vector(7 downto 0);

num:in std_logic_vector(1 downto 0);

clk:in std_logic;

col:out std_logic_vector(7 downto 0)

);

end entity;

architecture struct of led is

signal counter : integer range 0 to 7;

begin

process(clk)

begin

if clk'event and clk = '1' then

if counter = 7 then

counter <= 0;

else

counter <= counter +1;

end if;

end if;

end process;

process(clk,counter)

begin

if clk'event and clk = '0' then

if num <= "00" then

case counter is

when 0 => row <= "11111110"; col <= "00111100";

when 1 => row <= "11111101"; col <= "00111100";

when 2 => row <= "11111011"; col <= "00111100";

when 3 => row <= "11110111"; col <= "00111100";

when 4 => row <= "11101111"; col <= "00111100";

when 5 => row <= "11011111"; col <= "00011000";

when 6 => row <= "10111111"; col <= "00111100";

when 7 => row <= "01111111"; col <= "00011000";

end case;

elsif num = "01" then

case counter is

when 0 => row <= "11111110"; col <= "11111111";

when 1 => row <= "11111101"; col <= "11111111";

when 2 => row <= "11111011"; col <= "11111111";

when 3 => row <= "11110111"; col <= "11111111";

when 4 => row <= "11101111"; col <= "01000010";

when 5 => row <= "11011111"; col <= "01000010";

when 6 => row <= "10111111"; col <= "01000010";

when 7 => row <= "01111111"; col <= "00111100";

end case;

elsif num = "10" then

case counter is

when 0 => row <= "11111110"; col <= "00000000";

when 1 => row <= "11111101"; col <= "00011111";

when 2 => row <= "11111011"; col <= "00011111";

when 3 => row <= "11110111"; col <= "00011111";

when 4 => row <= "11101111"; col <= "10011111";

when 5 => row <= "11011111"; col <= "10001000";

when 6 => row <= "10111111"; col <= "10001000";

when 7 => row <= "01111111"; col <= "01110000";

end case;

else

case counter is

when 0 => row <= "11111110"; col <= "00011000";

when 1 => row <= "11111101"; col <= "00111100";

when 2 => row <= "11111011"; col <= "00011000";

when 3 => row <= "11110111"; col <= "00011000";

when 4 => row <= "11101111"; col <= "00111100";

when 5 => row <= "11011111"; col <= "00111100";

when 6 => row <= "10111111"; col <= "00111100";

when 7 => row <= "01111111"; col <= "00011000";

end case;

end if;

end if;

end process;

end struct;

//数码管的输出

library ieee;

use _logic_;

entity seg is

port(

r:in std_logic;

clk:in std_logic;

cat:out std_logic_vector(5 downto 0);

a:out std_logic_vector(6 downto 0);

w:in std_logic;

input:in std_logic_vector(3 downto 0);

num:in std_logic_vector(2 downto 0)

);

end entity;

architecture struct of seg is

signal a0,a1,a2,a3,a4,a5,ao:std_logic_vector(3 downto 0);

signal int:std_logic;

signal counter:integer range 0 to 5;

begin

process(w,r,int)

begin

if r= '1' or int = '0' then

a0<="1111";

a1<="1111";

a2<="1111";

a3<="1111";

a4<="1111";

a5<="1111";

int <= '1';

elsif w'event and w = '1' then//符合频率的情况下才能够实现相应的密码显示

case num is

when "000" => a0 <=input;

when "001" => a1 <=input;

when "010" => a2 <=input;

when "011" => a3 <=input;

when "100" => a4 <=input;

when "101" => a5 <=input;

when others=> NULL;

end case;

end if;

end process;

process(clk)

begin

if clk'event and clk = '1' then

if counter = 5 then

counter <= 0;

else

counter <= counter+1;

end if;

end if;

end process;//选通的计数

process(clk,counter)

begin

if clk'event and clk = '0' then

case counter is

when 0 => cat <= "111110";ao<=a0;

when 1 => cat <= "111101";ao<=a1;

when 2 => cat <= "111011";ao<=a2;

when 3 => cat <= "110111";ao<=a3;

when 4 => cat <= "101111";ao<=a4;

when 5 => cat <= "011111";ao<=a5;

end case;

end if;

end process;

process(ao)

begin

case ao is

when "0000" => a<="1111110";

when "0001" => a<="0110000";

when "0010" => a<="1101101";

when "0011" => a<="1111001";

when "0100" => a<="0110011";

when "0101" => a<="1011011";

when "0110" => a<="1011111";

when "0111" => a<="1110000";

when "1000" => a<="1111111";

when "1001" => a<="1111011";

when "1010" => a<="0000001";

when others => a<="0000000";

end case ;

end process;

end struct;

 功能说明

能够实现

1、密码设置:通过键盘进行4 位数字密码设定输入,在数码管上显示所输入数字。通过密码设置确定键(BTN 键)进行锁定。

2、开锁:在闭锁状态下,可以输入密码开锁,且每输入一位密码,在数码管上显示“-”,

提示已输入密码的位数。输入四位核对密码后,按“开锁”键,若密码正确则系统

开锁,若密码错误系统仍然处于闭锁状态,并用蜂鸣器或led 闪烁报警。

3、在开锁状态下,可以通过密码复位键(BTN 键)来清除密码,恢复初始密码“0000”。

闭锁状态下不能清除密码,此时按下复位键的时候会发出警报。

4、用点阵显示开锁和闭锁状态。

6、输入密码数字由右向左依次显示,即:每输入一数字显示在最右边的数码管上,同时

将先前输入的所有数字向左移动一位。

 故障及问题分析

1、在实现功能的时候,在按BTN键的时候会很费力,并且有时候会误读为多次摁键。

问题分析:在调节防抖的时候要根据每个板子的不同多次进行调整,防抖部分不够完善会致使相关情况出现。

2、仿真过程中无法实现仿真

问题分析:未去除分频器

 总结及结论

本次实验实现密码输入、密码校验、密码设置和更改等功能。设计过程能够在设计完成后在QuartusⅡ环境下进行电路的模拟仿真,反馈结果可以验证程序设计的可行性与可靠性。

本密码锁控制器设置的是4位串行安全输入的密码,在系统复位后,用户按键4次,输入一个完整的密码串,输入完后,系统会进行比对,如果发现密码吻合,则开锁,否则要求用户继续输入,如果连输入的密码串是错误的,则系统报警。

在软件、硬件设计和仿真过程中间我们也遇到不少问题,但最终还是把它们解决了,使得

设计符合要求。除了自己思考设计之外,这与和同学的同心协力的合作与讨论是分不开的的。相互的探讨使得我们的思路更加开阔,解决问题的办法也更多。总之,此次课程设计让我收益良多,同时因为有了实践操作,对课程所学内容也有了更深的记忆和理解,对数字电路技术和VHDL语言能够更好的掌握和应用了。