毕业设计(论文)基于VHDL的电子密码锁的设计.doc
摘要FPGA/VHDL是近几年集成电路中发展最快的产品。由于FPGA性能的高速发展以及设计人员自身能力的提高,可编程逻辑器件供应商将进一步扩大可编程芯片的领地,将复杂的专用芯片挤向高端和超复杂应用。据IC Insights的数据显示,FPGA市场从1999年的29亿美元增长到去年的56亿美元,几乎翻了一番。Matas预计这种高速增长局面以后很难出现,但可编程逻辑器件依然是集成电路中最具活力和前途的产业。本文介绍的VHDL密码锁应具有如下功能:密码预先存入寄存器中,开锁时,输入密码存入另一寄存器中,当按下“确定”键时,启动比较器,比较两个寄存器中的内容,当结果相同时开锁;当结果不同时不开锁。用户需要修改密码时,先开锁,再按“设定密码”,清除预先存入的密码,通过键盘输入新的2位十进制码,按“确定”完成。关键词:VHDL,密码锁,矩阵目录摘要1目录2一、 设计要求3二 电路组成3三 功能电路的设计41、总体设计框图42、键盘接口电路43时序产生电路64键盘扫描电路75键盘消抖电路86键盘译码电路107按键存储电路13(1)SISO串行输入/串行输出14(2)SIPO-串行输入/并行输出15(3)PISO-并行输入/串行输出16(4)PIPO-并行输入/并行输出178密码设置和比较模块189电锁控制电路设计19(1)数字按键输入部分19(2)功能键输入部分19(3)三种工作模式19附件1:程序清单20一、 设计要求设计一个简单的数字电子密码锁,密码为6位。功能1、 密码输入:每按下一个键,要求在数码管上显示,并依次左移;2、密码清除:清除密码输入,并将输入置为”000000”;3、密码修改:将当前输入设为新的密码;4、上锁和开锁。二 电路组成为达到以上功能,可将电子密码锁分为以下几个模块:1、键盘接口电路键盘矩阵、键盘扫描、键盘消抖、键盘译码及按键存储。2、电锁控制电路:数字按键输入、存储及清除。功能按键的设计。密码清除、修改与存储。电锁的激活与解除。3、输出显示电路BCD 译码、动态扫描电路。三 功能电路的设计1、总体设计框图2、键盘接口电路矩阵式键盘工作原理:矩阵式键盘是一种常见的输入装置,在计算机、电话、手机、微波炉等各工电子产品中被广泛应用。如图所示为一3×4 矩阵式键盘。矩阵式键盘以行、列形式排列,图中为4 行3 列,键盘上的每一个按键盘其实是一个开关电路,当某键被按下时,该按键所对应的位置就呈现逻辑0 的状态,键盘的扫描可以以行扫或列扫方式进行,图中为行扫方式,KEYR3KEYR0 为扫描信号,其中的某一位为0 即扫描其中的一行,具体见表1-1.键盘扫描信号KEYR3 与第一行相连,KEYR2 与第二行相连,依此类推。很显然,扫描信号的变化顺序为:0111、1011、1101、1110,周而复始。在扫描的过程中,当有键按下时,对应的键位就为逻辑0状态,从而从KEYC2.0 读出的键值相应列为0.具体情况如表1-2 所示:若从KEYC2.0 读出的值全为1 时,表示没有键被按下,则不进行按键的处理。如果的键被按下,则将KEYC2.0 读出的送至键盘译码电路进行译码。表1-2 键盘扫描与其对应的键值的关系时序产生电路:时序电路的产生:在一个系统的设计中,往往需要多种时钟信号,最为方便的方法是利用一个自由计数器来产生各种需要的频率。本电路需要:系统主时钟、消抖取样时钟和动态扫描时钟。3时序产生电路有如下VHDL 程序,请分析其输出结果:LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;USE IEEE.STD_LOGIC_ARITH.ALL ;USE IEEE.STD_LOGIC_UNSIGNED.ALL ;ENTITY free_counter ISPORT (CLK : IN STD_LOGIC ;CLK_A : OUT STD_LOGIC ;CLK_B : OUT STD_LOGIC_VECTOR(1 DOWNTO 0) ;END free_counter ;ARCHITECTURE a OF free_counter ISSIGNAL Q : STD_LOGIC_VECTOR(6 DOWNTO 0);BEGINPROCESS (CLK)BEGINIF CLK'EVENT AND CLK = '1' THENQ <= Q + 1;END IF;END PROCESS;CLK_A <= Q(1) ;CLK_B <= Q(4 DOWNTO 3) ;END a ;分析:首选信号Q 建立一个9 位自由计数器,对输入主时钟进行降频处理;使用CLK_A<=Q(1)语句,取得一个脉冲波形,对主时钟进行2 分频,其值为0、1、0、1;使用CLK_B<=Q(4 DOWNTO 3)语句,取得一脉冲序列,依次为00、01、10、11、00.;4键盘扫描电路目标:提供键盘扫描信号,即表1-1 中的KEYR3.0,变化顺序依次为0111、1011、1101、1110.。依次重复出现。程序清单:LIBRARY ieee;USE ieee.std_logic_1164.ALL;USE IEEE.STD_LOGIC_ARITH.ALL ;USE IEEE.STD_LOGIC_UNSIGNED.ALL ;ENTITY scan ISPORT (CLK : IN STD_LOGIC ;CLK_SCAN : OUT STD_LOGIC_VECTOR (3 downto 0);END scan ;ARCHITECTURE a OF scan ISSignal S : STD_LOGIC_VECTOR(1 DOWNTO 0);SIGNAL Q: STD_LOGIC_VECTOE(3 DOWNTO 0);BeginPROCESS (Clk)BeginIF CLK'Event AND CLK='1' thenQ <= Q+1;S :=Q(3 DOWNTO 2);END IF;END PROCESS;-排错!SCAN_OUT<= "1110" WHEN S=0 ELSE"1101" WHEN S=1 ELSE"1011" WHEN S=2 ELSE"0111" WHEN S=3 ELSE"1111"END a ;说明:程序中,S 信号是用来产生扫描信号的四个状态,Q 是为了对输入主时钟进行降频处理。5键盘消抖电路因为按键大多是机械式开关,在开关切换的瞬间会在接解点出现来回弹跳的现象,其现象可用图1-2表示:由图可见,虽然只是按了一次键,实际产生的按键信号却不只跳动一次,经过取样信号的检查后,将会造成误码判,认为是按了两次键。如果调整取样频率,可以发现抖现象得到了改善。按键信号:取样信号:取样结果:调整取样频率后的情况如下:程序清单:LIBRARY ieee;USE ieee.std_logic_1164.ALL;LIBRARY altera;USE altera.maxplus2.ALL;ENTITY debouncing ISPORT(d_in, clk : IN STD_LOGIC;dd1, dd0, qq1, qq0 : OUT STD_LOGIC ;d_out,d_out1 : OUT STD_LOGIC);END debouncing ;ARCHITECTURE a OF debouncing ISsignal vcc, inv_d : std_logic ;signal q0, q1 : std_logic ;signal d1, d0 : std_logic ;BEGINvcc <= '1' ;inv_d <= not d_in ;dff1 : dff PORT MAP (d =>vcc , q => q0 , clk => clk, clrn => inv_d , prn => vcc);dff2 : dff PORT MAP (d =>vcc , q => q1, clk => clk, clrn => q0 , prn => vcc);process (clk)beginif clk'event and clk='1' thend0 <= not q1;d1 <= d0;end if ;end process ;dd0 <= d0; dd1 <= d1; qq1 <= q1; qq0 <= q0;d_out <= not (d1 and not d0);d_out1 <= not q1 ;END a;6键盘译码电路从前面所述的键盘扫描电路的输出可以看出,扫描得到的信号规律性不强,例如数字键主要用来输入数字,但键盘扫描输出无法拿来直接使用,必须对其进行译码才能使用。如表所示,只要使用casewhen 或when else 语句,便可完成设计。键盘译码程序清单:LIBRARY ieee;USE ieee.std_logic_1164.ALL;USE IEEE.STD_LOGIC_ARITH.ALL ;USE IEEE.STD_LOGIC_UNSIGNED.ALL ;-*ENTITY KEYBOARD_DEC1 ISPORT (clk : IN STD_LOGIC ;CLK_KEYBOARD : IN STD_LOGIC_VECTOR (1 downto 0);C: IN STD_LOGIC_VECTOR (2 downto 0); -key code after debounceout_numb : OUT STD_LOGIC_VECTOR(3 downto 0); - for numb. keyout_func : OUT STD_LOGIC_VECTOR(3 downto 0); - for func. keyflag_numb : OUT STD_LOGIC ; -flag for numb. keyflag_func : OUT STD_LOGIC -flag for func. keyKEYR3.0 KEYC2.0 对应的按键 译码输出 功能011 1 0001 数码输入0111 101 2 0010 数码输入110 3 0011 数码输入011 4 0100 数码输入1011 101 5 0101 数码输入110 6 0110 数码输入011 7 0111 数码输入1101 101 8 1000 数码输入110 9 1001 数码输入011 0 0100 激活电锁1110 101 0000 数码输入110 00017);END KEYBOARD_DEC1 ;-*ARCHITECTURE a OF KEYBOARD_DEC1 ISsignal FF : std_logic ; -FLAG OF FUNC.signal FN : std_logic ; -FLAG OF NUMB.signal Z : std_logic_VECTOR(4 downto 0) ; -SCAN CODEsignal F : std_logic_VECTOR(3 downto 0) ; -FOR FUNC. CODEsignal N : std_logic_VECTOR(3 downto 0) ; -FOR NUMB. CODEBEGINPROCESS(clk)beginZ <= CLK_KEYBOARD & C ;IF CLK'EVENT AND CLK = '1' THENcase Z iswhen "11101" => N <= "0000" ;-0when "00011" => N <= "0001" ;-1when "00101" => N <= "0010" ;-2when "00110" => N <= "0011" ;-3when "01011" => N <= "0100" ;-4when "01101" => N <= "0101" ;-5when "01110" => N <= "0110" ;-6when "10011" => N <= "0111" ;-7when "10101" => N <= "1000" ;-8when "10110" => N <= "1001" ;-9when others => N <= "1111" ;end case ;END IF ;-*IF CLK'EVENT AND CLK = '1' THENcase Z iswhen "11011" => F <= "0100" ;-*_LOCKwhen "11110" => F <= "0001" ;-#_UNLOCKwhen others => F <= "1000" ;end case ;END IF ;end process ;FN <= NOT ( N(3) AND N(2) AND N(1) AND N(0) ) ;FF <= ( NOT F(3) AND F(2) AND NOT F(1) AND NOT F(0) OR (NOT F(3) AND NOT F(2) ANDNOT F(1) AND F(0) ) ;-CONNECTIONFLAG_NUMB <= FN ;8FLAG_FUNC <= FF ;OUT_NUMB <= N ;OUT_FUNC <= F ;END a;说明:1、键盘译码电路除了负责将键盘送出的数据进行译码外,另外就是在译码的同时,必须判别所按下的是数字键还是功能键。2、若为数字键,则 flag_numb=1,且out_num 输出BCD 码,并送往显示电路。3、若为功能键,则 flag_func=1,且out_func 输出4 位码,并送往电锁控制电路。7按键存储电路因为每次按键都会产生新的数据,可能会覆盖前面的数据,所以需要一个按键存储电路,将键盘扫描译码后的结果记录下来。这一功能可以用移位寄存器来实现。常见的移位寄存器的下列四种:A.串行输入/串行输出(SISO)B.串行输入/并行输出(SIPO)C.并行输入/串行输出(PISO)D.并行输入/并行输出(PIPO)(1)SISO串行输入/串行输出LIBRARY ieee;USE ieee.std_logic_1164.ALL;ENTITY siso ISPORT(DATA_IN :IN STD_LOGIC;CLK :IN STD_LOGIC;DATA_OUT :OUT STD_LOGIC);END siso ;ARCHITECTURE a OF siso ISSIGNAL Q: STD_LOGIC_VECTOR(3 DOWNTO 0);BEGINPROCESS(CLK)BEGINIF CLK'EVENT AND CLK = '1' THENQ(0) <= DATA_IN;FOR I IN 1 TO 3 LOOPQ(I) <= Q(I-1);END LOOP;END IF;END PROCESS;DATA_OUT <= Q(3);END a;(2)SIPO-串行输入/并行输出LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;USE IEEE.STD_LOGIC_ARITH.ALL ;USE IEEE.STD_LOGIC_UNSIGNED.ALL ;ENTITY sipo ISPORT(D_IN :IN STD_LOGIC;CLK :IN STD_LOGIC;D_OUT :OUT STD_LOGIC_VECTOR(3 DOWNTO 0);END sipo;ARCHITECTURE a OF sipo ISSIGNAL Q: STD_LOGIC_VECTOR(3 DOWNTO 0);BEGINPROCESS(CLK)BEGINIF CLK'EVENT AND CLK = '1' THENQ(0) <= D_IN;FOR I IN 1 TO 3 LOOPQ(I) <= Q(I-1);END LOOP;END IF;END PROCESS;D_OUT <= Q;END a;(3)PISO-并行输入/串行输出LIBRARY ieee;USE ieee.std_logic_1164.ALL;ENTITY piso ISPORT(DATA_IN :IN STD_LOGIC_VECTOR(3 DOWNTO 0);CLK :IN STD_LOGIC;nLOAD :IN STD_LOGIC;DATA_OUT :OUT STD_LOGIC);END piso;ARCHITECTURE a OF piso ISSIGNAL Q: STD_LOGIC_VECTOR(3 DOWNTO 0);BEGINPROCESS(nLOAD,CLK)BEGINIF nLOAD = '0' THENQ <= DATA_IN;ELSIF CLK'EVENT AND CLK = '1' THENq(1) <= Q(0) ;FOR I IN 1 TO 3 LOOPQ(I) <= Q(I-1);END LOOP;END IF;END PROCESS;PROCESS(nLOAD,CLK)BEGINIF nLOAD = '0' THENDATA_OUT <= '0'ELSIF CLK'EVENT AND CLK = '1' THENDATA_OUT <= Q(3);END IF;END PROCESS;END a;(4)PIPO-并行输入/并行输出LIBRARY ieee;USE ieee.std_logic_1164.ALL;USE IEEE.STD_LOGIC_ARITH.ALL ;USE IEEE.STD_LOGIC_UNSIGNED.ALL ;ENTITY piso ISPORT(DATA_IN :IN STD_LOGIC_VECTOR(3 DOWNTO 0);CLK :IN STD_LOGIC;DATA_OUT :OUT STD_LOGIC_VECTOR(3 DOWNTO 0);END piso;ARCHITECTURE a OF piso ISSIGNAL Q: STD_LOGIC_VECTOR(3 DOWNTO 0);BEGINPROCESS(nLOAD,CLK)BEGINIF CLK'EVENT AND CLK = '1' THENQ<=DATA_IN;DATA_OUT<=Q;END IF;END PROCESS;END a;8密码设置和比较模块该模块代码如下:process (a,reset,q,enter,set,clk)beginif clk='1' and clk'event thenif reset='1' then ab<='0'elsif enter='1' thenif set='1' thennum<=q;dv<=a;elsIF dv=a and q=num then ab<='1'elsif qr<3 then qr<=qr+1;else alarm<=1;end if;end if;if ab<='1' and lockopen='1' then opn<='1'elsif reset='1' then opn<='0'else opn<='0'end if;end if;end procee;该模块由一个进程描述。设计思想是当按下#键后,如果紧接着按下*键,则系统记录在此之前所输入的数字作为设定的密码,这一功能是一方面用dv<=a 来实现十位十进制数的锁存,另一方面用num<=q 语句来记录实际输入的要设定的密码位数,我认为这是一种用简单代码实现密码位数可随意更改的功能的较好的方法;当按下#键后,如果紧接着没有按下*键,则系统就将刚才输入的数字与原来设定的密码进行比较,如果正确则会在紧接着按下lockopen键后控制opn引脚输出高点平驱动开锁电磁铁开锁;如果输入密码错误,则在按下lockopen键后不进行开锁操作并使错误密码输入次数计数器qr 加一,并通过qr 不等于零驱动时间记录模块记录下错误密码输入的次数和时间,同时等待下一次密码输入,如果qr=3 即累记记录下错误密码输入次数达到三次,则系统通过信号alarm 驱动报警模块发出警报。9电锁控制电路设计电锁控制电路是整个电路的控制中心,主要完成如下功能:(1)数字按键输入部分 如果输入数字键,第一个数字会从显示器的最右端开始显示,此后每新按一个数字时,显示器上的数字必须往左移动一位。 若想要更改输入的数字,可按退格键来清除前一个输入的数字,或按清除键清除输入的所有数字,再重新输入4 位数字。 既然设计的是四位电子密码锁,当输入的数字键超过 4 位时,电路不应理会。(2)功能键输入部分 退格键:只清除前一个输入的数字。 清除键:清除所有输入。 密码核对:在密码更改,开锁之前必须先核对密码。 密码变更:按下此键将目前输入的数字设定为新的密码。 激活电锁:上锁,上锁之前必须先设定密码才能上锁。 解除电锁:检查输入的密码是否正确,正确才开锁。 万用密码:电锁维护者使用。(3)三种工作模式附件1:程序清单-*-LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;USE IEEE.STD_LOGIC_ARITH.ALL ;USE IEEE.STD_LOGIC_UNSIGNED.ALL ;LIBRARY altera;USE altera.maxplus2.ALL;-*ENTITY elec_lock ISPORT (CLK_4M : IN STD_LOGIC ; -system original clock 4M输入文字模式输入 4 位数字退格及清除上锁工作模式:(输入密码)、密码核对、变更密码、存储密码及激活上锁。开锁工作模式:(输入密码)、密码核对、开锁。CLK_SCAN : OUT STD_LOGIC_VECTOR (3 downto 0) ; -scan sequenceKEY_IN : IN STD_LOGIC_VECTOR (2 downto 0) ; -KEY IN button codeFLAG_NUMB : OUT STD_LOGIC ;FLAG_FUNC : OUT STD_LOGIC ;LED_COM : OUT STD_LOGIC ; - for LP-2900 onlyCLEAR : OUT STD_LOGIC ; -*ENLOCK : OUT STD_LOGIC ; -1:LOCK, 0:UNLOCKNUMB_CNT : OUT STD_LOGIC_VECTOR (2 DOWNTO 0) ;BCD_CODE : OUT STD_LOGIC_VECTOR (15 DOWNTO 0) ;SELOUT : OUT STD_LOGIC_VECTOR (1 DOWNTO 0) ; -FIT TO LP-2900SEGOUT : OUT STD_LOGIC_VECTOR(6 DOWNTO 0) - SEG7 Display);END elec_lock ;-*ARCHITECTURE a OF elec_lock IScomponent debouncingport( d_in : IN STD_LOGIC ;clk : IN STD_LOGIC ;d_out : OUT STD_LOGIC ) ;end component ;SIGNAL CLK : STD_LOGIC ;SIGNAL CLK_KEYBOARD : STD_LOGIC_VECTOR(1 downto 0) ;SIGNAL CLK_DEBOUNCE : STD_LOGIC ;SIGNAL CLK_DISPLAY : STD_LOGIC_VECTOR(1 downto 0) ;SIGNAL C : STD_LOGIC_VECTOR(2 downto 0) ;SIGNAL N : STD_LOGIC_VECTOR(3 downto 0) ;SIGNAL F : STD_LOGIC_VECTOR(3 downto 0) ;SIGNAL FN : STD_LOGIC ;SIGNAL FF : STD_LOGIC ;SIGNAL SEL : STD_LOGIC_VECTOR (3 downto 0) ;SIGNAL OUT_NUMB : STD_LOGIC_VECTOR(3 downto 0) ;SIGNAL OUT_FUNC : STD_LOGIC_VECTOR(3 downto 0) ;SIGNAL ACC : STD_LOGIC_VECTOR (15 DOWNTO 0) ;SIGNAL REG : STD_LOGIC_VECTOR (15 DOWNTO 0) ;SIGNAL RR2 : STD_LOGIC ; - * RR2 = ClearSIGNAL QA, QB, BB : STD_LOGIC ;SIGNAL NC : STD_LOGIC_VECTOR (2 DOWNTO 0) ;SIGNAL DB : STD_LOGIC_VECTOR( 3 DOWNTO 0);- Number TO DisplaySIGNAL SEG : STD_LOGIC_VECTOR( 6 DOWNTO 0);- SEG7 Display SignalBEGIN-*- CONNECTIONOUT_NUMB <= N ;OUT_FUNC <= F ;FLAG_NUMB <= FN ;FLAG_FUNC <= FF ;CLK_DEBOUNCE <= CLK ;NUMB_CNT<= NC ;SEGOUT(6 DOWNTO 0) <= SEG; - Seven Segment DisplaySELOUT <= CLK_DISPLAY ;LED_COM <= '1' ; -For LP-2900 only-*- scan signal generatorcounter : blockSignal Q : STD_LOGIC_VECTOR(22 DOWNTO 0);Signal S : STD_LOGIC_VECTOR(1 DOWNTO 0) ; -keyboard scan about 15Hz *SIGNAL SEL : STD_LOGIC_VECTOR (3 downto 0);BEGINPROCESS (Clk_4M)BeginIF CLK_4M'Event AND CLK_4M = '1' thenQ <= Q+1;END IF;END PROCESS;CLK <= Q(0) ; -CLK = CLK_DEBOUNCECLK_KEYBOARD <= Q(5 DOWNTO 4) ; - *00-01-10-11CLK_DISPLAY <= Q(5 DOWNTO 4) ;- To generate keyboard scan sequence 1110->1101->1011->0111SEL <= "1110" WHEN CLK_KEYBOARD=0 ELSE"1101" WHEN CLK_KEYBOARD=1 ELSE"1011" WHEN CLK_KEYBOARD=2 ELSE"0111" ;CLK_SCAN <= SEL ;end block counter ;-*-debounuing cktdebounuing : blockbeginU1: debouncing PORT MAP (d_in => key_in(0) ,d_out => C(0) ,clk => CLK);U2: debouncing PORT MAP (d_in => key_in(1) ,d_out => C(1) ,clk => CLK);U3: debouncing PORT MAP (d_in => key_in(2) ,d_out => C(2) ,clk => CLK);END block debounuing ;-*-key_decoderkey_decoder : blocksignal Z : std_logic_VECTOR(4 downto 0) ; -KEY POSITIONSIGNAL R1, R0 : STD_LOGIC ;beginPROCESS(clk)beginZ <= CLK_KEYBOARD & C ;IF CLK'EVENT AND CLK = '1' THENcase Z iswhen "11101" => N <= "0000" ;-0when "00011" => N <= "0001" ;-1when "00101" => N <= "0010" ;-2when "00110" => N <= "0011" ;-3when "01011" => N <= "0100" ;-4when "01101" => N <= "0101" ;-5when "01110" => N <= "0110" ;-6when "10011" => N <= "0111" ;-7when "10101" => N <= "1000" ;-8when "10110" => N <= "1001" ;-9when others => N <= "1111" ;end case ;END IF ;-*IF CLK'EVENT AND CLK = '1' THENcase Z iswhen "11011" => F <= "0100" ;-*_LOCKwhen "11110" => F <= "0001" ;-#_UNLOCKwhen others => F <= "1000" ;end case ;END IF ;end process ;FN <= NOT ( N(3) AND N(2) AND N(1) AND N(0) ) ;FF <= ( NOT F(3) AND F(2) AND NOT F(1) AND NOT F(0) OR (NOT F(3) AND NOT F(2)AND NOT F(1) AND F(0) ) ;-To generate clear signal for ACCPROCESS (CLK)BEGINIF CLK'EVENT AND CLK = '1' THENR1 <= R0 ; R0 <= FF ;END IF ;RR2 <= R1 AND NOT R0 ;CLEAR <= RR2 ;END PROCESS ;end block key_decoder ;-*-KEYIN / BACK / ALL CLEARKEYIN_PROCESS :BLOCKSIGNAL RST,D0,D1: STD_LOGIC ;BEGINPROCESS(CLK,FN,RST)BEGINIF RST = '1' THENACC <= "0000000000000000" ; -CLEAR INPUTNC <= "000" ;ELSEIF FN'EVENT AND FN = '1' THENIF NC < 4 THENACC <= ACC(11 DOWNTO 0) & N ;BB <= '0' ;NC <= NC + 1 ;ELSEBB <= '1' ;END IF ;END IF ;END IF ;END PROCESS ;RST <= RR2 ;END BLOCK KEYIN_PROCESS ;-*LOCK_PROCESS : BLOCKBEGINP