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语言能够更好的掌握和应用了。
发布评论