设计四数字电子密码锁doc.docx
《设计四数字电子密码锁doc.docx》由会员分享,可在线阅读,更多相关《设计四数字电子密码锁doc.docx(21页珍藏版)》请在冰豆网上搜索。
设计四数字电子密码锁doc
数字电子密码锁
一、设计目的与要求:
目的:
掌握矩阵式键盘的工作原理、设计方法;掌握译码器的应用;掌握状态机的设计方法,掌握数码管的控制。
要求:
设计一个数字电子密码锁,密码为3位,密码锁由键盘控制,显示采用数码管及LED灯。
功能:
1、密码输入:
每按下一个数字键,要求在数码管上显示,并依次左移;输入错误时,按退格键,清除前一个输入的数字;输入完毕,按确认键。
2、开锁:
按开锁键,检查输入的密码是否正确,正确才开锁,成功。
3、上锁:
按上锁键,可以直接上锁或者设定新密码上锁。
4、密码修改:
按下修改键,必须先核对原密码,正确后可以输入3位数字,设为新的密码。
5、报警:
开锁输入密码,连续错误三次,则禁止输入密码,并发出报警信号,用红灯一直亮表示。
6、解除报警:
按复位键,解除报警状态,实际应用中复位键设置在其他部位,不可设置在键盘上。
7、万能密码:
电锁维护者使用,在程序中暂时统一设置为999。
8、其他要求:
输入键盘为矩阵式,不使用直接式;条件允许时可以使用语音模块代替指示灯的表示。
二、电路组成:
为达到以上功能,可将数字电子密码锁分为以下几个模块:
1、键盘接口电路:
键盘矩阵、键盘扫描、键盘消抖、键盘译码及按键存储。
2、密码锁控制电路:
数字按键输入、存储及清除;
功能按键的设计:
退格键、确认键、开锁键、上锁键、修改键、解除报警键;
密码清除、修改与存储。
密码锁的上锁与开锁。
3、输出显示电路
BCD译码、动态扫描电路、指示灯电路(或者为语音控制电路)。
三、功能电路的设计:
1、键盘接口电路:
图1
(1)矩阵式键盘工作原理:
矩阵式键盘是一种常见的输入装置,在计算机、电话、手机、微波炉等各工电子产品中被广泛应用。
如图2所示为一4×4矩阵式键盘。
矩阵式键盘以行、列形式排列,图中为4行4列,键盘上的每一个按键盘其实是一个开关电路,当某键被按下时,该按键所对应的位置就呈现逻辑0的状态,键盘的扫描可以以行扫或列扫方式进行,图中为行扫方式,KEYR3—KEYR0为扫描信号,其中的某一位为0即扫描其中的一行,具体见表1。
表1键盘扫描与其对应的键值的关系
KEYR3..0
KEYC3..0
对应的按键
KEYR3..0
KEYC3..0
对应的按键
0111
0111
7
1101
0111
1
1011
8
1011
2
1101
9
1101
3
1110
开锁键
1110
密码修改键
1011
0111
4
1110
0111
0
1011
5
1011
#
1101
6
1101
退格键
1110
上锁键
1110
确认键
键盘扫描信号KEYR3与第一行相连,KEYR2与第二行相连,依此类推。
很显然,扫描信号的变化顺序为:
0111、1011、1101、1110,周而复始。
在扫描的过程中,当有键按下时,对应的键位就为逻辑0状态,从而从KEYC3..0读出的键值相应列为0,具体情况如表1所示。
若从KEYC3..0读出的值全为1时,表示没有键被按下,则不进行按键的处理。
如果的键被按下,则将KEYC3..0读出的送至键盘译码电路进行译码。
(2)时钟产生电路
在一个系统的设计中,往往需要多种时钟信号,最方便的方法是利用一个自由计数器来产生各种需要的频率。
本电路需要:
系统主时钟CLK、扫描状态产生时钟clkouta和动态扫描时钟clkoutb,其中系统主时钟CLK为输入时钟,由20MHZ晶振产生。
程序清单:
LIBRARYieee;
USEieee.std_logic_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYclkdivIS
PORT(CLK:
INSTD_LOGIC;
clkouta,clkoutb:
OUTSTD_LOGIC);
ENDclkdiV;
ARCHITECTURErtlOFclkdiVIS
SIGNALCLKA:
STD_LOGIC;
Begin
PROCESS(CLK)
VARIABLES:
INTEGERRANGE200DOWNTO0;
Begin
IFCLK'EventANDCLK='1'then
IFS<200THEN
S:
=S+1;
CLKA<='0';
ELSES:
=0;
CLKA<='1';
ENDIF;
ENDIF;
ENDPROCESS;
PROCESS(CLKA)
VARIABLES:
INTEGERRANGE100DOWNTO0;
Begin
IFCLKA'EventANDCLKA='1'then
IFS<10THEN
S:
=S+1;
CLKOUTa<='0';
clkoutb<='0';
ELSIFS<20THEN
S:
=S+1;
CLKOUTa<='1';
CLKOUTb<='0';
ELSIFS<50THEN
S:
=S+1;
CLKOUTa<='1';
CLKOUTb<='1';
ELSIFS<70THEN
S:
=S+1;
CLKOUTa<='1';
CLKOUTb<='0';
ELSIFS<100THEN
S:
=S+1;
CLKOUTa<='0';
CLKOUTb<='0';
ELSES:
=0;
ENDIF;
ENDIF;
ENDPROCESS;
endrtl;
说明:
CLK时钟经过两次分频,得到扫描状态产生时钟clkouta和动态扫描时钟clkoutb均是1KHZ,但是扫描状态产生时钟clkouta的高电平部分完全包含动态扫描时钟clkoutb的高电平部分,目的在于先使用时钟clkouta的上升沿产生扫描状态的变化,再使用时钟clkoutb的上升沿产生键盘扫描信号。
仿真波形:
(3)键盘扫描电路
目标:
提供键盘扫描信号SCAN_OUT,即表1中的KEYR3..0,变化顺序依次为0111、1011、1101、1110....依次重复出现。
程序清单:
LIBRARYieee;
USEieee.std_logic_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYscanIS
PORT(CLKA,CLKB:
INSTD_LOGIC;
SCAN_STATE:
OUTSTD_LOGIC_VECTOR(1DOWNTO0);
SCAN_OUT:
OUTSTD_LOGIC_VECTOR(3downto0));
ENDscan;
ARCHITECTURErtlOFscanIS
SIGNALS:
STD_LOGIC_VECTOR(1DOWNTO0);
Begin
PROCESS(CLKA)
Begin
IFCLKA'EventANDCLKA='1'then
S<=S+1;
ENDIF;
ENDPROCESS;
PROCESS(CLKB,S)
Begin
IFCLKB'EventANDCLKB='1'then
CASESIS
WHEN"00"=>SCAN_OUT<="1110";
WHEN"01"=>SCAN_OUT<="1101";
WHEN"10"=>SCAN_OUT<="1011";
WHEN"11"=>SCAN_OUT<="0111";
WHENOTHERS=>SCAN_OUT<="1111";
ENDCASE;
SCAN_STATE<=S;
ENDIF;
ENDPROCESS;
ENDrtl;
说明:
程序中,S信号是用来产生扫描信号的四个状态SCAN_STATE:
00、01、10、11,再利用动态扫描时钟的上升沿产生扫描信号:
0111、1011、1101、1110。
仿真波形:
(4)键盘消抖电路
因为按键大多是机械式开关,在开关切换的瞬间会在接解点出现来回弹跳的现象,其现象可用图3表示。
由图可见,虽然只是按了一次键,实际产生的按键信号却不只跳动一次,将会造成误码判,认为是按了两次键。
如果调整取样时钟周期,可以发现抖现象得到了改善。
通过时序图可见:
在按键过程中可能有三种情况发生,
抖动发生在时钟的某个上升沿,此时的输入信号为低电平,则输出为低电平;
抖动发生在时钟的某个上升沿,但此时的输入信号抖动为高电平,由于按键(低电平)时间通常在200ms以上,则在下一个上升沿输出为低电平;
抖动发生在时钟信号的两个相邻上升沿之间,则在第二个上升沿输出高电平。
释放键盘时的情况类似,可见,只要时钟周期大于抖动时间而远小于按键时间,去抖电路即可正确识读按键次数。
一般键盘在被按下和释放时会造成持续时间不大于10ms的信号抖动,而按键时间通常在200ms以上,所以可以使用较低频率的时钟信号作为消抖时钟。
程序清单:
LIBRARYieee;
USEieee.std_logic_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYdebouncingIS
PORT
(clkSCAN:
INSTD_LOGIC;
d_in:
INSTD_LOGIC_VECTOR(3DOWNTO0);
d_out:
OUTSTD_LOGIC_VECTOR(3DOWNTO0));
ENDdebouncing;
ARCHITECTUREaOFdebouncingIS
signalTEMPA,TEMPB,TEMPC,TEMPD,TEMPE:
STD_LOGIC_VECTOR(3DOWNTO0);
signalCOUNT:
STD_LOGIC_VECTOR(3DOWNTO0);
BEGIN
process(clkSCAN)
begin
ifclkSCAN'eventandclkSCAN='0'then
TEMPA<=D_IN;
IFTEMPE=D_INTHEN
IFCOUNT>="1000"THEN
COUNT<="1000";
D_OUT<=D_IN;
ELSE
COUNT<=COUNT+1;
D_OUT<="1111";
ENDIF;
ELSE
COUNT<="0000";
D_OUT<="1111";
ENDIF;
ENDIF;
endprocess;
process(clkSCAN)
begin
ifclkSCAN'eventandclkSCAN='1'then
TEMPB<=TEMPA;
TEMPC<=TEMPB;
TEMPD<=TEMPC;
TEMPE<=TEMPD;
ENDIF;
ENDPROCESS;
ENDa;
说明:
将d_in信号去抖后送给D_OUT,其中d_in信号的变化规律是四个扫描时钟周期内仅有一个时钟周期为输入按键值,其余时间保持为“1111”。
仿真波形:
(5)键盘译码电路
从前面的键盘扫描电路的输出可以看出,扫描得到的信号规律性不强,例如数字键主要用来输入数字,但键盘扫描输出无法拿来直接使用,必须对其进行译码才能使用,如表1所示。
程序清单:
LIBRARYieee;
LIBRARYieee;
USEieee.std_logic_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYKEYBOARD_DECIS
PORT(
clkSCAN:
INSTD_LOGIC;
S:
INSTD_LOGIC_VECTOR(1downto0);
d_IN:
INSTD_LOGIC_VECTOR(3downto0);--keycodeafterdebounce
out_numb:
OUTSTD_LOGIC_VECTOR(3downto0));
ENDKEYBOARD_DEC;
--******************************************************
ARCHITECTUREaOFKEYBOARD_DECIS
signalZ:
std_logic_VECTOR(5downto0);--SCANCODE
BEGIN
Z<=S&d_IN;
PROCESS(clkSCAN)
begin
IFCLKSCAN'EVENTANDCLKSCAN='0'THEN
caseZis
when"110111"=>out_numb<="0000";--0
when"100111"=>out_numb<="0001";--1
when"101011"=>out_numb<="0010";--2
when"101101"=>out_numb<="0011";--3
when"010111"=>out_numb<="0100";--4
when"011011"=>out_numb<="0101";--5
when"011101"=>out_numb<="0110";--6
when"000111"=>out_numb<="0111";--7
when"001011"=>out_numb<="1000";--8
when"001101"=>out_numb<="1001";--9
when"111101"=>out_numb<="1010";--BACKSPACE
when"111110"=>out_numb<="1011";--ENTER
when"101110"=>out_numb<="1100";--MODIFYNUM
when"011110"=>out_numb<="1101";--LOCK;
when"001110"=>out_numb<="1110";--UNLOCK;
whenothers=>out_numb<="1111";
endcase;
ENDIF;
endprocess;
ENDa;
说明:
键盘译码电路根据键盘输入数据d_IN和扫描状态S进行译码out_numb,数字键为:
0、1、2、3、4、5、6、7、8、9,功能键为:
退格键、确认键、修改键、上锁键和解锁键,out_numb=“1111”表示无任何操作。
仿真波形:
(6)按键存储电路
键盘译码后,可以看出,译码值不等于“1111”时表示有按键动作发生,当译码值等于长时间“1111”时,表示无按键动作发生,所以可以根据译码值产生按键动作发生的标示信号和按键的译码值。
程序清单:
LIBRARYieee;
USEieee.std_logic_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYnum_or_fun_DECIS
PORT(
clkSCAN:
INSTD_LOGIC;
in_num:
INSTD_LOGIC_VECTOR(3downto0);
change_clk:
outSTD_LOGIC;
out_num:
OUTSTD_LOGIC_VECTOR(3downto0));
ENDnum_or_fun_DEC;
--******************************************************
ARCHITECTUREaOFnum_or_fun_DECIS
signaltemp_num:
STD_LOGIC_VECTOR(3downto0);
BEGIN
PROCESS(clkSCAN)
variablecount,counta:
std_logic_vector(2downto0);
begin
IFCLKSCAN'EVENTANDCLKSCAN='1'THEN
ifin_num="1111"then
ifcount<7then
count:
=count+1;
else
change_clk<='0';
count:
="111";
counta:
="000";
endif;
else
temp_num<=in_num;
count:
="000";
if(counta<3)then
counta:
=counta+1;
else
counta:
="011";
change_clk<='1';
endif;
endif;
ENDIF;
endprocess;
out_num<=temp_num;
ENDa;
说明:
当按键译码值in_num不等于“1111”时,按键发生标示信号change_clk='1',按键译码输出值out_num等于按键译码值。
仿真波形:
2、电锁控制电路设计
电锁控制电路是整个电路的控制中心,主要完成如下功能:
1、数字按键输入部分
如果输入数字键,第一个数字会从显示器的最右端开始显示,此后每新按一个数字时,显示
器上的数字必须往左移动一位。
若想要更改输入的数字,可按退格键来清除前一个输入的数字,或按清除键清除输入的所有
数字,再重新输入3位数字。
既然设计的是三位电子密码锁,当输入的数字键超过3位时,电路不应理会。
2、功能键输入部分
退格键:
清除前一个输入的数字,如果数字全部清除,则回到前一个状态(例如上锁或者解锁等)。
密码核对:
在密码更改,开锁之前必须先核对密码。
密码修改:
按下此键先输入原密码,核对后将新输入的数字设定为新的密码。
上锁:
按上锁键可以直接上锁。
解锁:
检查输入的密码是否正确,正确才开锁。
万用密码:
电锁维护者使用。
程序清单:
三位电子密码锁
LIBRARYieee;
USEieee.std_logic_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYcontrolIS
PORT(reset,d_clk:
instd_logic;
d_in:
INSTD_LOGIC_VECTOR(3downto0);
led_alarm:
outstd_logic;
led_flag,leda,ledb,ledc:
inoutSTD_LOGIC_VECTOR(3downto0)
);
ENDcontrol;
--******************************************************
ARCHITECTUREaOFcontrolIS
TYPESTATE_TYPEIS(lock_idle,lock,unlock_idle,unlock,modify,new_num,alarm,num_one,
num_two,num_three);
SIGNALstate:
STATE_TYPE;
signallock_rega,lock_regb,lock_regc:
std_logic_vector(3downto0);
signallocked,unlock_modify_flag:
std_logic;
BEGIN
PROCESS(reset,state,d_in,d_clk)
variablealarmcnt:
std_logic_vector(1downto0);
BEGIN
ifreset='0'then
state<=lock_idle;
leda<="1111";
ledb<="1111";
ledc<="1111";
alarmcnt:
="00";
locked<='0';
led_flag<="0000";
unlock_modify_flag<='0';
lock_rega<="0001";
lock_regb<="0001";
lock_regc<="0001";
elsif(d_clk'eventandd_clk='1')then
iflocked='0'then
CASEstateIS
WHENlock_idle=>IFd_in="1110"then--unlock
state<=unlock;
led_flag<="1000";
unlock_modify_flag<='0';
leda<="0000";
ledb<="0000";
ledc<="0000";
ELSifd_in="1100"then--modify
state<=modify;
led_flag<="0010";
unlock_modify_flag<='1';
leda<="0000";
ledb<="0000";
ledc<="0000";
ELSE
led_flag<="0000";
leda<="1111";
ledb<="1111";
ledc<="1111";
ENDIF;
WHENunlock=>ifd_in="1010"then--lock_idle
state<=lock_IDLE;
led_flag<="0000";
leda<="1111";
ledb<="1111";
ledc<="1111";
ELSifd_in<"1010"then--num_one
state<=num_one;
leda<=d_in;
ENDIF;
WHENnum_one=>IFd_in="1010"then--backspace
leda<="0000";
ledb<="0000";
ledc<="0000";
caseled_flagis
when"1000"=>state<=unlock;
when"0100"=>state<=lock;
when"0010"=>state<=modify;
when"0001"=>state<=new_num;
whenothers=>null;
endcase;
ELSifd_in<"1010"then--num_two
state<=num_two;
leda<=d_in;
ledb<=leda;
ENDIF;
WHENnum_two