设计并实现一个数字密码锁,密码锁有四位数字密码和一个确认开锁按键,密码输入正确,密码锁打开,密码输入错误进行警示。
基本要求:
1、密码设置:通过键盘进行4 位数字密码设定输入,在数码管上显示所输入数字。通过密码设置确定键(BTN 键)进行锁定。
2、开锁:在闭锁状态下,可以输入密码开锁,且每输入一位密码,在数码管上显示“-”,提示已输入密码的位数。输入四位核对密码后,按“开锁”键,若密码正确则系统开锁,若密码错误系统仍然处于闭锁状态,并用蜂鸣器或led 闪烁报警。
3、在开锁状态下,可以通过密码复位键(BTN 键)来清除密码,恢复初始密码“0000”。闭锁状态下不能清除密码。
4、用点阵显示开锁和闭锁状态。
提高要求:
1、输入密码数字由右向左依次显示,即:每输入一数字显示在最右边的数码管上,同时将先前输入的所有数字向左移动一位。
2、密码锁的密码位数(4~6 位)可调。
3、自拟其它功能。
出于对于此密码锁安全性、可控性及便利性的优化,本人对于题目要求做了如下调整:
1、通过一个拨码开关VISIBLE(可视化),来实现对数码管输入数字是否可见的控制:开时,输入密码数字由右向左依次显示,即每输入一数字显示在最右边的数码管上,同时将先前输入的所有数字向左移动一位;关时,数码管显示“-”提示输入密码的位数,并有四个LED灯用8421码提示输入密码的键值。
2、将密码复位键在功能上优化成密码更改键CHGPW(change password的缩写),当处于开锁状态时,按下此键即在开锁状态下获得设置密码的权限,点阵显示为不同颜色的开锁图案。因为原要求中相当于设定过一次密码后只能通过密码复位键将密码设置为0000,这既不合理又不方便。
3、对于提高要求的取舍:
(1)将移位显示结合在了开关VISIBLE中,并拓展了四个LED的键值显示。
(2)舍弃了对于密码位数可调的扩展性。
(3)自拟了输入时的退格键DEL以及全清键CLR,用以避免在输入时误操作导致报警,一定程度上增强了密码锁的可控性和实用性。
整体思路上用有限状态机实现该课题(set,unlocked,locked)。
具体需要如下模块:分频模块、键值读取模块、状态机主控制模块、点阵显示模块、数码管显示模块以及报警模块。
(1)输入:CLK:时钟信号。
VISIBLE(SW0):控制密码可视化的拨码开关。
RST(SW7):重置密码锁内部很多进程,但并不重置密码锁本身。
LOCK(BTN1):由开锁状态转换为闭锁状态的闭锁键。
CHGPW(BTN4):在开锁状态下跳至开锁并设置密码状态。
OK(BTN0):设置或输入密码后的确认键。
DEL(BTN2):在设置或输入密码时清除一位的退格键。
CLR(BTN3):在设置或输入密码时清除全部的全清键。
KEYROW:四位输入行信号。
(2)输出:KEYCOL:四位输出列扫描信号。
DISP:六位输出数码管位数显示信号。
SHOWAN:8位输出数码管内容显示信号。
CODE:四位LED输出用8421码表示键值。
DISROW:点阵行输出信号。
DISCOLR:点阵红列输出信号。
DISCOLG:点阵绿列输出信号。
SOUND:报警声音输出信号。
LIGHTS:报警闪灯输出信号。
3.总体框图
块间信号说明
type state_type is(set,unlocked,locked); --定义状态机状态类型
signal state:state_type:=set; --状态机的状态
signal pwed,pwing:std_logic_vector(15 downto 0); --已设定的密码和正在输入的密码
signal count:integer range 0 to 4:=0; --输入密码位数计数器
signal div:std_logic_vector(29 downto 0); --30位分频器
signal keycode:std_logic_vector(3 downto 0); --键值
signal keyscan:std_logic_vector(3 downto 0); --键盘列扫描信号
signal keyrow:std_logic_vector(3 downto 0); --键盘行信号
signal keyloc:std_logic_vector(7 downto 0); --键位信号
signal alarm:std_logic:='0'; --报警信号 及 退格键防抖辅助信号
(1)分频模块
process(clk,rst) --divider
begin
if(rst='1')then
div<="000000000000000000000000000000";--2^30
elsif(clk'event and clk='1')then
div<=div+1;
end if;
end process;
用一个30位标准逻辑向量的div信号实现任意2的N次幂分频,对于时间精度要求不高的系统,无需过于准确的分频,这种精度是完全够用的,而避免了过多对于分频器的编程。使用该分频器时,用DIV(N)或DIV(N DOWNTO N-M)就可以实现所需要的分频。如DIV(9)为原时钟信号的29+1约等于1000分频。
(2)键值读取模块
keycol<=keyscan;
process(div(21 downto 20)) --key scaning
begin
case div(21 downto 20)is
when"00"=>keyscan<="0111";
when"01"=>keyscan<="1011";
when"10"=>keyscan<="1101";
when"11"=>keyscan<="1110";
end case;
end process;
process(keyscan,keyrow,keycode,keyloc) --keycode
begin
keyloc<=keyrow & keyscan;
case keyloc is
when"01111110"=>keycode<="0001";
when"01111101"=>keycode<="0010";
when"01111011"=>keycode<="0011";
when"01110111"=>keycode<="0100";
when"10111110"=>keycode<="0101";
when"10111101"=>keycode<="0110";
when"10111011"=>keycode<="0111";
when"10110111"=>keycode<="1000";
when"11011110"=>keycode<="1001";
when"11011101"=>keycode<="0000";
when others=>keycode<="1111";
end case;
end process;
按一定频率输出列扫描,并返回行信号,当行列信号同时有一列为零时,表示该键被按下,用连接的行列信号确定按键位置进一步确定键值,当没有按键按下时,键值为“1111”即15。
(3)状态机主控制模块(代码见于源代码部分)
分频信号上升沿时,判断状态机状态,进入不同的处理,set状态设定密码,count计数输入位数,满四位后确认则设置成功进入解锁状态,直至闭锁进入闭锁状态,可输入密码并确认,正确则开锁,错误则继续闭锁并且报警直至输入正确进入开锁状态。开锁状态下也可选择更改密码选项进入设置密码状态,设置密码状态和闭锁输入密码状态下可通过退格键和全清键对以输入的密码进行清除。
密码储存于16位标准逻辑向量PWING,每四位以8421码存储一位密码,输入时通过对密码后12位和新输入的键值连接,使该位密码存入PWING(3 DOWNTO 0),删除时通过对1111和密码前12位连接,使原来的PWING(15 DOWNTO 4)移位至PWING(11 DOWNTO 0),密码设置成功时PWED<=PWING,保存密码,留以输入密码时对比。
(4)点阵显示模块(代码见于源代码部分)
判断三种状态分别在点阵上扫描显示不同的内容(颜色或图案)。
(5)数码管显示模块(代码见于源代码部分)
判断三种状态,开锁状态时数码管不显示,闭锁输入密码或设置密码状态下判断VISIBLE,不可视时判断COUNT值,显示不同位数的“-”,可视时判断COUNT循环扫描当前位数的几位密码。
(6)报警模块(代码见于源代码部分)
但密码错误时ALARM信号置一,直至密码正确时再置为零。另一进程以ALARM为输入信号,控制LIGHTS和SOUND的报警。
对于该部分,由于仿真存在的延时以及仿真需要的时间过长,而控制密码锁(设置密码闭锁输入密码等)需要的时间过长,因此对CLK时钟信号做一定调整并适当改变分频比,而后进行分模块的仿真。
(1)分频模块
时钟信号CLK为25MHz,周期40ns。
即可实现任意2N分频。
(2)键值读取模块
为了不用过长的时间仿真,将列扫描信号的频率增大到时钟频率,但由于仿真延时等问题存在,所以仿真结果并不完全准确,但仍可见列信号为扫描输出信号,行信号均为1时,键值为“1111”即15,而当有按键按下时,相应行信号为“0”,即CODEOUT出现了0~9的各种数字,其余时候没有键摁下,键值为“1111”。
(3)点阵显示模块
显示内容为橙色的开锁图标,表示设置密码。
01100000 00011000
10010000 00100100
10010000 00100100
10010000 00100100
00111111 01111110
00111111 01111110
00111111 01111110
00111111 01111110
开锁状态为绿色的开锁图标,闭锁状态为红色的闭锁图标,同理。
(4)报警模块
当报警信号为“1”时,两只LED灯以DIV(18)的频率轮流闪烁,蜂鸣器以该频率作为间隔发生,而决定声音音高的频率为DIV(14)。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity elecpwlock is
port
(
clk,chgpw,lock,visible,ok,clr,rst,del:in std_logic; --外部端口说明已在上述内容中写过
keyrow:in std_logic_vector(3 downto 0); --故此处不再赘述
keycol:out std_logic_vector(3 downto 0);
lights:out std_logic_vector(1 downto 0):="00";
code:out std_logic_vector(3 downto 0):="0000";
sound:out std_logic:='0';
discolr,discolg,disrow,showan:out std_logic_vector(7 downto 0);
disp:out std_logic_vector(5 downto 0)
);
end elecpwlock;
architecture elecpwlock_arch of elecpwlock is --信号功能及含义也已经写过
type state_type is(set,unlocked,locked); --亦不再赘述
signal state:state_type:=set;
signal pwed,pwing:std_logic_vector(15 downto 0);
signal count:integer range 0 to 4:=0;
signal div:std_logic_vector(29 downto 0);
signal keycode:std_logic_vector(3 downto 0);
signal keyscan:std_logic_vector(3 downto 0);
signal keyloc:std_logic_vector(7 downto 0);
signal alarm:std_logic:='0';
begin
keycol<=keyscan;
process(clk,rst) --divider
begin
if(rst='1')then
div<="000000000000000000000000000000";--2^30
elsif(clk'event and clk='1')then
div<=div+1;
end if;
end process;
process(div(21 downto 20)) --key scaning 循环扫描输出键盘列值
begin
case div(21 downto 20)is
when"00"=>keyscan<="0111";
when"01"=>keyscan<="1011";
when"10"=>keyscan<="1101";
when"11"=>keyscan<="1110";
end case;
end process;
process(keyscan,keyrow,keycode,keyloc) --keycode 由行标列标共同确定位置和键值
begin
keyloc<=keyrow & keyscan;
case keyloc is
when"01111110"=>keycode<="0001";
when"01111101"=>keycode<="0010";
when"01111011"=>keycode<="0011";
when"01110111"=>keycode<="0100";
when"10111110"=>keycode<="0101";
when"10111101"=>keycode<="0110";
when"10111011"=>keycode<="0111";
when"10110111"=>keycode<="1000";
when"11011110"=>keycode<="1001";
when"11011101"=>keycode<="0000";
when others=>keycode<="1111";
end case;
end process;
process(div,chgpw,lock,visible,ok,clr,keycode) --state control
begin
if(div(19)'event and div(19)='1')then
case state is
when set=>
if(keycode/="1111" and count<4)then --尚未输够四位切键值不为1111
pwing<=pwing(11 downto 0) & keycode;
code<=keycode;
count<=count+1;
elsif(clr='1')then --全清
count<=0;
pwing<="1111111111111111";
code<="0000";
elsif(del='1')then --退格(清一位)
pwing<="0000" & pwing(15 downto 4);
if(count=0)then
count<=0;
elsif(count=1 or count=2 or count=3 or count=4)then
count<=count-1;
end if;
elsif(count=4 and ok='1')then --输入四位并确定
state<=unlocked;
pwed<=pwing;
pwing<="1111111111111111";
code<="0000";
else
state<=set;
end if;
when unlocked=>
if(lock='0' and chgpw='0')then --无操作 保持开锁
state<=unlocked;
elsif(lock='0' and chgpw='1')then --更改密码
state<=set;
count<=0;
elsif(lock='1' and chgpw='0')then --将电子锁闭锁
state<=locked;
count<=0;
pwing<="1111111111111111";
end if;
when locked=> --对于闭锁状态输入和设置输入相同
if(keycode/="1111" and count<4)then
pwing<=pwing(11 downto 0) & keycode;
count<=count+1;
code<=keycode;
elsif(clr='1')then
count<=0;
pwing<="1111111111111111";
elsif(del='1')then
pwing<="0000" & pwing(15 downto 4);
if(count=0)then
count<=0;
elsif(count=1 or count=2 or count=3 or count=4)then
count<=count-1;
end if;
end if;
if(ok='1' and pwed=pwing)then --确定时密码正确则开锁(解除报警)
state<=unlocked;
alarm<='0';
code<="0000";
elsif(ok='1' and pwed/=pwing)then --密码不正确则报警直至正确
state<=locked;
count<=0;
alarm<='1';
code<="0000";
end if;
end case;
end if;
end process;
process(state,div(12 downto 10)) --dot matrix display
begin
case state is
when locked =>
case div(12 downto 10) is
when "000" => disrow<="11111110"; discolr<="00011000";discolg<="00000000";
when "001" => disrow<="11111101"; discolr<="00100100";discolg<="00000000";
when "010" => disrow<="11111011"; discolr<="00100100";discolg<="00000000";
when "011" => disrow<="11110111"; discolr<="00100100";discolg<="00000000";
when "100" => disrow<="11101111"; discolr<="01111110";discolg<="00000000";
when "101" => disrow<="11011111"; discolr<="01111110";discolg<="00000000";
when "110" => disrow<="10111111"; discolr<="01111110";discolg<="00000000";
when "111" => disrow<="01111111"; discolr<="01111110";discolg<="00000000";
when others => null;
end case;
when unlocked =>
case div(12 downto 10) is
when "000" => disrow<="11111110"; discolg<="01100000";discolr<="00000000";
when "001" => disrow<="11111101"; discolg<="10010000";discolr<="00000000";
when "010" => disrow<="11111011"; discolg<="10010000";discolr<="00000000";
when "011" => disrow<="11110111"; discolg<="10010000";discolr<="00000000";
when "100" => disrow<="11101111"; discolg<="00111111";discolr<="00000000";
when "101" => disrow<="11011111"; discolg<="00111111";discolr<="00000000";
when "110" => disrow<="10111111"; discolg<="00111111";discolr<="00000000";
when "111" => disrow<="01111111"; discolg<="00111111";discolr<="00000000";
when others => null;
end case;
when set =>
case div(12 downto 10) is
when "000" => disrow<="11111110"; discolr<="01100000"; discolg<="01100000";
when "001" => disrow<="11111101"; discolr<="10010000"; discolg<="10010000";
when "010" => disrow<="11111011"; discolr<="10010000"; discolg<="10010000";
when "011" => disrow<="11110111"; discolr<="10010000"; discolg<="10010000";
when "100" => disrow<="11101111"; discolr<="00111111"; discolg<="00111111";
when "101" => disrow<="11011111"; discolr<="00111111"; discolg<="00111111";
when "110" => disrow<="10111111"; discolr<="00111111"; discolg<="00111111";
when "111" => disrow<="01111111"; discolr<="00111111"; discolg<="00111111";
when others => null;
end case;
end case;
end process;
process(alarm,div) --alarm
begin
if(alarm='1')then
lights(1)<=div(22); --LED闪烁报警频率
lights(0)<=not div(22);
if(div(22)='1')then --此频率决定蜂鸣器发声的时间间隔
sound<=div(14); --此频率决定蜂鸣器的音调
elsif(div(22)='0')then
sound<='0';
end if;
elsif(alarm='0')then
lights<="00";
sound<='0';
end if;
end process;
process (div(11 downto 10),state,pwing,count,visible) --num display
begin
case state is
when set=>
if(visible='1')then --是否密码可见
case count is
when 0=> --已输0位,数码管都不显示
disp<="111111";
when 1=> --1位,最后一个数码管显示最后一位密码
disp<="111110";
case pwing(3 downto 0) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when 2=> --多位循环扫描显示各位密码
case div(10) is
when '0'=>
disp<="111110";
case pwing(3 downto 0) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when '1'=>
disp<="111101";
case pwing(7 downto 4) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
end case;
when 3=>
case div(11 downto 10) is
when "00"=>
disp<="111110";
case pwing(3 downto 0) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "01"=>
disp<="111101";
case pwing(7 downto 4) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "10"=>
disp<="111011";
case pwing(11 downto 8) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "11"=>
disp<="111111";
end case;
when 4=>
case div(11 downto 10) is
when "00"=>
disp<="111110";
case pwing(3 downto 0) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "01"=>
disp<="111101";
case pwing(7 downto 4) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "10"=>
disp<="111011";
case pwing(11 downto 8) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "11"=>
disp<="110111";
case pwing(15 downto 12) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
end case;
end case;
elsif(visible='0')then
showan<="00000001";
case count is
when 0=>disp<="111111";
when 1=>disp<="111110";
when 2=>disp<="111100";
when 3=>disp<="111000";
when 4=>disp<="110000";
when others=>null;
end case;
end if;
when locked=>
if(visible='1')then
case count is
when 0=>
disp<="111111";
when 1=>
disp<="111110";
case pwing(3 downto 0) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when 2=>
case div(10) is
when '0'=>
disp<="111110";
case pwing(3 downto 0) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when '1'=>
disp<="111101";
case pwing(7 downto 4) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
end case;
when 3=>
case div(11 downto 10) is
when "00"=>
disp<="111110";
case pwing(3 downto 0) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "01"=>
disp<="111101";
case pwing(7 downto 4) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "10"=>
disp<="111011";
case pwing(11 downto 8) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "11"=>
disp<="111111";
end case;
when 4=>
case div(11 downto 10) is
when "00"=>
disp<="111110";
case pwing(3 downto 0) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "01"=>
disp<="111101";
case pwing(7 downto 4) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "10"=>
disp<="111011";
case pwing(11 downto 8) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
when "11"=>
disp<="110111";
case pwing(15 downto 12) is
when "0001" => showan<="00110000";
when "0010" => showan<="01101101";
when "0011" => showan<="01111001";
when "0100" => showan<="00110011";
when "0101" => showan<="01011011";
when "0110" => showan<="01011111";
when "0111" => showan<="01110000";
when "1000" => showan<="01111111";
when "1001" => showan<="01111011";
when "0000" => showan<="01111110";
when others => showan<="00000000";
end case;
end case;
end case;
elsif(visible='0')then
showan<="00000001";
case count is
when 0=>disp<="111111";
when 1=>disp<="111110";
when 2=>disp<="111100";
when 3=>disp<="111000";
when 4=>disp<="110000";
when others=>null;
end case;
end if;
when unlocked=>
disp<="111111";
showan<="00000000";
end case;
end process;
end elecpwlock_arch;
最终实现了该课题的预期目标,详见于课题基本要求、提高要求以及个人对于实验要求的优化与取舍。
资源利用情况如下:
利用了214个逻辑器件,61个管脚。
对于这种较为综合的实验,要说完全没有遇到一些一时想不通的困难是不可能的,而我印象最深的瓶颈期就是在思考如何获取多次的键值。键值的翻译为随时的,即当有按键按下时键值会在1111和该键值间循环(因为列信号处于循环扫描的状态,当列信号为0的列与按键不对应时,行信号仍为“1111”,键值为“1111”;只有列信号扫描到与按下的键相对应的那一列时,行信号才会有一位低电平,键值不为“1111”)。这时就要考虑以怎样的条件获得一位密码才是最合适的,如果获取的条件太严苛,可能导致很难存入以为密码,比如需要按过长的时间;反之如果条件太宽泛,则可能导致在我按下一个按键时读入几位相同的密码。于是我最先想到的解决方法给扫描信号一个适当的频率,然后通过信号沿来实现密码读入的控制,然而四位行值都有可能由1变0,并且同一进程不能由多个信号的边沿来控制,为此我有试图写入不同的进程,可又被“不能在不同的进程对同一信号进行赋值”所限制。我甚至还想过将四位行信号相异或成为一位,可最终这种方法也遇到了其他的问题。
当时面对这个问题我几近绝望,最后还是借鉴了其他同学的方法,那就是用几个合适的分频来限制键值的读取,但难免会遇到我上述说过的“按键时间短则无效,按键时间长则连续输入多个”的问题。但我明确地知道,如果以一个工程一个产品的角度去想,这无疑严重地影响了其便利性。试想,当我变更密码时,由于一次按键被读入两个我将需要输完四位再确定并重新变更密码,这将是多么糟糕的用户体验!而更令人无法接受的是,当我在闭锁状态下由于一个操作不够精准而误输入,我竟然无法避免地要让我自己的密码锁报警?或许我不能说这样的产品不合格,但绝不优秀!而我们已有的产品是如何做的呢?于是退格键和全清键的构思和实现就成了必不可少的一部分。或者我可以这样说,这种看似扩展的提高功能实际上是对一些基本功能漏洞的优化,甚至不太好听的说是弥补乃至于掩饰。不过庆幸的是,这样做下来,我的用户体验并不糟糕(虽然操作上变的更复杂,但是给人功能更全面的感觉)。
实验能让我们工科生培养严谨的思维、良好的编程习惯以及对各种细节的注重这种话虽然有些宽泛但绝对毋庸置疑。试想你拆东墙补西墙,弥补一个漏洞接着又一个漏洞的时候,一定决心下次考虑的更周全吧?试想你今天写的代码由于命名词不达意或者大小写空行空格乱成一团导致第二天自己都看不懂了的时候,一定立志下次按照最规范的编程习惯来做这一切。试想你一个end,一个then,一个when others甚至一个“;”导致你的代码怎么都编译不过时,难道你不更情愿下次更谨慎地一次写好?我依旧不能说自己这些点做得好了,但无疑是在一次又一次的实验中有所进步了。这个课程并不容易,但也却因此会让我们受益良多。
然而要对这次的实验总结出一个以往实验总结中我不会用到的词,那便是“匠心”,这也是我这次实验课最大的收获和总结。从选题的那一刻开始,数字密码锁在我心中就不再仅仅是题目,而是一个由我来设计产品的工程,可能是此前的实验我没有如此用心过,我的心里甚至有点小激动,我不知道自己的放手一搏会有什么样的成果,但是我期待着,憧憬着。于是实验要求就像客户需求一样印在了我的脑海里,然后是些设计报告,那时我完全把它当作了一个产品来构思(更好的一点是可以自拟更多的拓展功能),于是我用手机屏幕锁来类比,当时就想到了“密码可视化”拨码开关和用以“清除”的按键(还差一点就写入了更改密码时需要验证两遍的功能,后来觉得既然密码可视的话这个功能比较鸡肋就舍掉了)。而后编程的过程中,我真的以工匠之心去处理我能想到的每一个细节(安全性、便利性以及可控性等等),我把自己当作用户去评价自己的产品,然后不断的优化用户体验以求达到最好的效果。然而从产品用户的角度,我不希望用户要来迎合产品繁复的操作亦或各种规则,我想要一切都随心所欲自然而然,要让我的产品去适应所有的用户(我甚至还让几个同学来玩玩我的电子锁然后提意见,毕竟是相对比较有实用性的一个课题)。或许自己在实验报告说出这种话还是很莫名其妙,我自己也觉得不可理喻,但是我的用心真的体现在了很多无关技术的细节上(比如我的开锁闭锁点阵显示,既美观又写实,两个状态的锁体和锁头尺寸和样式完全一致,就连锁头与锁体固定端的位置都是相同的,并且无论状态都是将整个点阵充分利用并占据了比较正中的位置)。可能对于工科生的数电课来说,这根本毫无可宣扬的理由,但我自己就是会莫名的开心,毕竟这真的是我最大最需要也最欣赏的收获,工匠之心,优化之美。
数电实验报告姓名所在学院专业班级学号日期目录一实验目的2二电路设计与验证2一用加法器实现2位乘法电路21任务分析22方案及结构设计…
数电实验报告班级学号姓名班内序号20xx年5月30日一实验内容及要求一Quartus原理图输入法设计1用逻辑门设计实现一个半加器仿…
实验一门电路逻辑功能及测试一实验目的1熟悉门电路逻辑功能2熟悉数字电路学习机及示波器使用方法二实验仪器及材料1双踪示波器2器件74…
目录汽车尾灯控制电路设计第一章设计指标3设计指标3第二章系统概述321设计思想322可行性论证523各功能的组成524总体工作过程…
北京邮电大学数字电路与逻辑设计实验实验名称学班姓学实验报告QuartusII原理图输入法设计与实现院级名号一实验名称Quartus…
数字电子技术实验总结心得数字电子技术是一门理论与实践密切相关的学科,如果光靠理论,我们就会学的头疼,如果借助实验,效果就不一样了,…
不知不觉,一个学期已经过去,数电实验这门课也即将结束。回顾这个学期以来在数电实验课程中的学习,我发现自己既收获了很多,也付出了很多…
数字电路课程设计数字定时器课程设计任务书1集成数字定时器2技术指标1设计一个数字定时器要求它具有数字钟的功能又可以按预定时刻发出控…
北京邮电大学数字电路与逻辑设计实验实验名称学班姓学实验报告QuartusII原理图输入法设计与实现院级名号一实验名称Quartus…
重庆交通大学综合性设计性实验报告班级学号姓名实验项目名称滤波器设计综合实验应用实验项目性质综合性设计实验所属课程数字信号处理实验室…