28_基于FPGA的简易电子密码锁

28_基于FPGA的简易电子密码锁

实验原理

设计一个密码锁的控制电路,当输入正确密码时,输出开锁信号,并同时用红灯亮、绿灯熄灭表示开锁;用绿灯亮、红灯熄灭表示关锁; 在锁的控制电路中储存一个可以修改的 4 位密码;从第一个按钮触动后的 5 秒内若未将锁打开,则电路自动复位并进入自锁状态,使之无法再打开,并由扬声器发出持续 20 秒的报警信号。

硬件原理图

实验代码

控制模块

-- ******************************************************************************

-- 控制模块

-- 操作步骤

-- 上电首先按下key5按键进行复位操作

-- (1)按下key3按键输入第一个密码,输入完第一个密码后按下key3;输入第二个密码,第二个密码输入完成后后按下key3

-- 输入第三个密码,第三个密码输入完成后后按下key3;输入第四个密码,第四个密码输入完成后后按下key3,输入完成;

-- (2)只有密码输入正确后才能进行修改密码;

-- (3)修改密码操作如下:

-- 按下key1进入修改密码状态,然后通过key2数字选择按键,每输入一个密码,按下key3按键一次,数码管跳至下一位,输入下一个密码,

-- 4个密码输入完成后按下key4按键,确定输入的密码就会重新装载进去。第三位数码管会显示当前输入的密码的次序。

-- 取消修改密码按下key5

-- *******************************************************************************

library IEEE;

use IEEE.std_logic_1164.all;

use IEEE.std_logic_unsigned.all;

use IEEE.std_logic_arith.all;

entity control is

port(

clk:in std_logic; --50M时钟输入

reset_n:in std_logic; --复位信号输入

set_signal:in std_logic; --设置密码按键

select_signal:in std_logic; --

ok_signal:in std_logic; --

set_ok_signal:in std_logic; --

 

fm_time_over:in std_logic; --蜂鸣器20秒相应完成信号

fm_20:in std_logic;

password1_out:out std_logic_vector(3 downto 0); --

password2_out:out std_logic_vector(3 downto 0); --

password3_out:out std_logic_vector(3 downto 0); --

password4_out:out std_logic_vector(3 downto 0); --

ok_signal_counter_out:out std_logic_vector(2 downto 0);--四个数码管的标号

motor_open:out std_logic; --电机开关标志

start_flag:out std_logic;

password_yes:out std_logic;

password_no:out std_logic;

password_set_out:out std_logic

);

end control;

architecture control_behave of control is

signal key_counter:std_logic_vector(3 downto 0); --按键按下次数计数器

signal password_set:std_logic; --设置密码标志,'1'为设置密码,'0'为没有设置密码

signal password_set_finish:std_logic; --密码设置成功信号

signal ok_signal_counter:std_logic_vector(2 downto 0);--输入密码个数计数器

signal current_password1:std_logic_vector(3 downto 0);--当前第一个密码

signal current_password2:std_logic_vector(3 downto 0);--当前第二个密码

signal current_password3:std_logic_vector(3 downto 0);--当前第三个密码

signal current_password4:std_logic_vector(3 downto 0);--当前第四个密码

signal current_password1_temp:std_logic_vector(3 downto 0);--当前第一个密码

signal current_password2_temp:std_logic_vector(3 downto 0);--当前第二个密码

signal current_password3_temp:std_logic_vector(3 downto 0);--当前第三个密码

signal current_password4_temp:std_logic_vector(3 downto 0);--当前第四个密码

signal password1:std_logic_vector(3 downto 0); --输入第一个密码

signal password2:std_logic_vector(3 downto 0); --输入第二个密码

signal password3:std_logic_vector(3 downto 0); --输入第三个密码

signal password4:std_logic_vector(3 downto 0); --输入第四个密码

signal set_signal_re1:std_logic;

signal set_signal_re2:std_logic;

signal password_yes_temp:std_logic;

signal password_no_temp:std_logic;

signal start_flag_reg:std_logic;

type state is(

prepare,--准备状态

start--开始状态

);

signal current_state:state;--一开始处于准备状态

 

type set_state is(

prepare,--准备状态

start--开始状态

);

signal current_set_state:set_state;--一开始处于准备状态

begin

password_set_out <= not password_set;

ok_signal_counter_out <= ok_signal_counter;

start_flag <= start_flag_reg;

-- //****************************************************************************************************

-- // 模块名称:产生设置密码信号password_set

-- // 功能描述:

-- //****************************************************************************************************

process(clk,reset_n)

begin

if(reset_n = '0')then

password_set <= '0';

current_set_state <= prepare;

 

current_password1 <= "0001";

current_password2 <= "0001";

current_password3 <= "0001";

current_password4 <= "0001";

 

elsif(clk'event and clk = '0')then--下降沿触发

if((password_yes_temp = '1'and password_no_temp = '0') or password_set = '1')then--只有输入密码正确后才能修改密码

case current_set_state is

when prepare=>

if(set_signal = '0')then

current_set_state <= start;

password_set <= '1';

else

current_set_state <= prepare;

password_set <= '0';

end if;

when start =>

if(set_ok_signal = '0')then--设置完成

--重新装载密码

current_password1 <= current_password1_temp;

current_password2 <= current_password2_temp;

current_password3 <= current_password3_temp;

current_password4 <= current_password4_temp;

current_set_state <= prepare;

password_set <= '0';

else

password_set <= '1';

current_set_state <= start;

end if;

when others=>null;

end case;

else

null;

end if;

end if;

end process;

-- //****************************************************************************************************

-- // 模块名称:违时信号的产生

-- // 功能描述:

-- //****************************************************************************************************

process(clk,reset_n)

begin

if(reset_n = '0')then

current_state <= prepare;

start_flag_reg <= '0';

elsif(clk'event and clk = '1')then--上升沿沿触发

if(password_set = '0')then--非设置密码状态

case current_state is

when prepare=>

if(select_signal = '0')then

start_flag_reg <= '1';

current_state <= start;

else

start_flag_reg <= '0';

current_state <= prepare;

end if;

when start=>

if(ok_signal_counter = "100")then--输入密码完成

start_flag_reg <= '0';

current_state <= prepare;

elsif(fm_time_over = '1')then--蜂鸣器响应20s完成

start_flag_reg <= '0';

current_state <= prepare;

else--两者未完成

start_flag_reg <= '1';

current_state <= start;

end if;

end case;

else

current_state <= prepare;

start_flag_reg <= '0';

end if;

end if;

end process;

-- //****************************************************************************************************

-- // 模块名称:产生按键输入数字

-- // 功能描述:

-- //****************************************************************************************************

process(select_signal,reset_n)

begin

if(reset_n = '0')then

key_counter <= "0000";

elsif(select_signal'event and select_signal = '0')then--下降沿触发

if(key_counter = "1001")then

key_counter <= "0000";

else

key_counter <= key_counter + '1';

end if;

end if;

end process;

-- //****************************************************************************************************

-- // 模块名称:统计输入密码的个数4

-- // 功能描述:

-- //****************************************************************************************************

process(ok_signal,reset_n)

begin

if(reset_n = '0')then

ok_signal_counter <= "000";

elsif(ok_signal'event and ok_signal = '0')then--下降沿触发

if(fm_20 = '0')then--在不违时的情况下可以进行输入密码

if(ok_signal_counter = "100")then

ok_signal_counter <= "001";

--密码输入完成

else

ok_signal_counter <= ok_signal_counter + '1';

end if;

else

ok_signal_counter <= "000";

end if;

end if;

end process;

-- //****************************************************************************************************

-- // 模块名称:存储输入密码的个数4

-- // 功能描述:

-- //****************************************************************************************************

process(clk,reset_n)

begin

if(reset_n = '0')then

----------------------------------

current_password1_temp <= "0000";

current_password2_temp <= "0000";

current_password3_temp <= "0000";

current_password4_temp <= "0000";

----------------------------------

password_yes_temp <= '0';

password_no_temp <= '1';

password1 <= "0000";

password2 <= "0000";

password3 <= "0000";

password4 <= "0000";

motor_open <= '1';--电机关

elsif(clk'event and clk = '1')then--上升沿触发

if(fm_20 = '0')then--在不违时的情况下可以进行输入密码

case ok_signal_counter is

when "001"=>

if(password_set = '0')then--非设置密码

password1 <= key_counter;

else--设置密码

current_password1_temp <= key_counter;

password1 <= "0000";

motor_open <= '1';--电机关

password_yes_temp <= '0';

password_no_temp <= '0';

end if;

when "010"=>

if(password_set = '0')then--非设置密码

password2 <= key_counter;

else--设置密码

current_password2_temp <= key_counter;

password2 <= "0000";

motor_open <= '1';--电机关

password_yes_temp <= '0';

password_no_temp <= '0';

end if;

when "011"=>

if(password_set = '0')then--非设置密码

password3 <= key_counter;

else--设置密码

current_password3_temp <= key_counter;

password3 <= "0000";

motor_open <= '1';--电机关

password_yes_temp <= '0';

password_no_temp <= '0';

end if;

when "100"=>

if(password_set = '0')then--非设置密码

password4 <= key_counter;

if(current_password1 = password1 and

current_password2 = password2 and

current_password3 = password3 and

current_password4 = password4)then

password_yes_temp <= '1';

password_no_temp <= '0';

motor_open <= '0';--电机开

else

password_yes_temp <= '0';

password_no_temp <= '1';

motor_open <= '1';--电机关

end if;

else--设置密码

current_password4_temp <= key_counter;

password4 <= "0000";

motor_open <= '1';--电机关

password_yes_temp <= '0';

password_no_temp <= '0';

end if;

when others=>null;

end case;

else

password_yes_temp <= '0';

password_no_temp <= '1';

password1 <= "0000";

password2 <= "0000";

password3 <= "0000";

password4 <= "0000";

motor_open <= '1';--电机关

end if;

end if;

end process;

-- 当处于设置密码状态时,两个灯是不亮的

password_yes <= not ((password_yes_temp) and (not password_set));--接绿色led141引脚

password_no <= not ((password_no_temp) and (not password_set));--接红色led142引脚

 

-- //****************************************************************************************************

-- // 模块名称:数码管显示数字选择模块

-- // 功能描述:

-- //****************************************************************************************************

process(reset_n,password_set,

current_password1_temp,current_password2_temp,current_password3_temp,current_password4_temp,

password1,password2,password3,password4)

begin

if(reset_n = '0')then

password1_out <= "0000";

password2_out <= "0000";

password3_out <= "0000";

password4_out <= "0000";

elsif(password_set = '1')then--设置密码

password1_out <= current_password1_temp;

password2_out <= current_password2_temp;

password3_out <= current_password3_temp;

password4_out <= current_password4_temp;

else--非设置密码

password1_out <= password1;

password2_out <= password2;

password3_out <= password3;

password4_out <= password4;

end if;

end process;

 

 

end control_behave;

 

数码管显示模块

-- ******************************************************************************

-- 计时模块

-- *******************************************************************************

library IEEE;

use IEEE.std_logic_1164.all;

use IEEE.std_logic_unsigned.all;

use IEEE.std_logic_arith.all;

entity time_counter is

port(

clk:in std_logic; --50M时钟输入

reset_n:in std_logic; --复位信号输入

password1_in:in std_logic_vector(3 downto 0); --

password2_in:in std_logic_vector(3 downto 0); --

password3_in:in std_logic_vector(3 downto 0); --

password4_in:in std_logic_vector(3 downto 0); --

ok_signal_counter_in:in std_logic_vector(2 downto 0);

 

seg_duan:out std_logic_vector(7 downto 0); --数码管段信号输出

seg_wei:out std_logic_vector(7 downto 0) --数码管位信号输出

);

end time_counter;

architecture time_counter_behave of time_counter is

signal clk_1hz: std_logic;

signal count: std_logic_vector(24 downto 0);

signal clk_scan: std_logic;

signal seg_select: std_logic_vector(2 downto 0);

signal scan_count: std_logic_vector(13 downto 0);

begin

-- //****************************************************************************************************

-- // 模块名称:50M时钟分频至1HZ模块

-- // 功能描述:

-- //****************************************************************************************************

process(clk,reset_n)

begin

if(reset_n = '0')then

clk_1hz <= '0';

count <= "0000000000000000000000000";

elsif(clk'event and clk = '1')then--上升沿触发

if(count = "1011111010111100001000000")then--

count <= "0000000000000000000000000";

clk_1hz <= not clk_1hz;

else

count <= count + '1';

end if;

end if;

end process;

-- //****************************************************************************************************

-- // 模块名称:数码管扫描时钟产生模块

-- // 功能描述:

-- //****************************************************************************************************

process(clk,reset_n)

begin

if(reset_n = '0')then

scan_count <= "00000000000000";

clk_scan <= '0';

elsif(clk'event and clk = '1')then--上升沿触发

if(scan_count = "10011100010000")then

scan_count <= "00000000000000";

clk_scan <= not clk_scan;

else

scan_count <= scan_count + '1';

end if;

end if;

end process;

process(clk_scan,reset_n)

begin

if(reset_n = '0')then

seg_select <= "000";

elsif(clk_scan'event and clk_scan = '1')then--上升沿触发

seg_select <= seg_select + '1';

end if;

end process;

-- //****************************************************************************************************

-- // 模块名称:数码管显示模块

-- // 功能描述:

-- //****************************************************************************************************

process(clk)

begin

if(clk'event and clk = '1')then--上升沿触发

case seg_select is

when "000"=>--显示第1个密码

seg_wei <= "11111110";

case password4_in is

when "0000"=>seg_duan <= "11000000";--0

when "0001"=>seg_duan <= "11111001";--1

when "0010"=>seg_duan <= "10100100";--2

when "0011"=>seg_duan <= "10110000";--3

when "0100"=>seg_duan <= "10011001";--4

when "0101"=>seg_duan <= "10010010";--5

when "0110"=>seg_duan <= "10000010";--6

when "0111"=>seg_duan <= "11111000";--7

when "1000"=>seg_duan <= "10000000";--8

when "1001"=>seg_duan <= "10010000";--9

when others=>null;

end case;

when "001"=>--显示第2个密码

seg_wei <="11111101";

case password3_in is

when "0000"=>seg_duan <= "11000000";--0

when "0001"=>seg_duan <= "11111001";--1

when "0010"=>seg_duan <= "10100100";--2

when "0011"=>seg_duan <= "10110000";--3

when "0100"=>seg_duan <= "10011001";--4

when "0101"=>seg_duan <= "10010010";--5

when "0110"=>seg_duan <= "10000010";--6

when "0111"=>seg_duan <= "11111000";--7

when "1000"=>seg_duan <= "10000000";--8

when "1001"=>seg_duan <= "10010000";--9

when others=>null;

end case;

when "010"=>--显示第3个密码

seg_wei <="11111011";

case password2_in is

when "0000"=>seg_duan <= "11000000";--0

when "0001"=>seg_duan <= "11111001";--1

when "0010"=>seg_duan <= "10100100";--2

when "0011"=>seg_duan <= "10110000";--3

when "0100"=>seg_duan <= "10011001";--4

when "0101"=>seg_duan <= "10010010";--5

when "0110"=>seg_duan <= "10000010";--6

when "0111"=>seg_duan <= "11111000";--7

when "1000"=>seg_duan <= "10000000";--8

when "1001"=>seg_duan <= "10010000";--9

when others=>null;

end case;

when "011"=>--显示第4个密码

seg_wei <="11110111";

case password1_in is

when "0000"=>seg_duan <= "11000000";--0

when "0001"=>seg_duan <= "11111001";--1

when "0010"=>seg_duan <= "10100100";--2

when "0011"=>seg_duan <= "10110000";--3

when "0100"=>seg_duan <= "10011001";--4

when "0101"=>seg_duan <= "10010010";--5

when "0110"=>seg_duan <= "10000010";--6

when "0111"=>seg_duan <= "11111000";--7

when "1000"=>seg_duan <= "10000000";--8

when "1001"=>seg_duan <= "10010000";--9

when others=>null;

end case;

when "100"=>--

seg_wei <="11011111";--显示当前输入密码的次序

case ('0' & ok_signal_counter_in) is

when "0000"=>seg_duan <= "11000000";--0

when "0001"=>seg_duan <= "11111001";--1

when "0010"=>seg_duan <= "10100100";--2

when "0011"=>seg_duan <= "10110000";--3

when "0100"=>seg_duan <= "10011001";--4

when "0101"=>seg_duan <= "10010010";--5

when "0110"=>seg_duan <= "10000010";--6

when "0111"=>seg_duan <= "11111000";--7

when "1000"=>seg_duan <= "10000000";--8

when "1001"=>seg_duan <= "10010000";--9

when others=>null;

end case;

when others=>null;

end case;

end if;

end process;

end time_counter_behave;

 

超时报警模块

-- ******************************************************************************

-- 按键模块,进行按键消抖和按键编码

-- *******************************************************************************

library IEEE;

use IEEE.std_logic_1164.all;

use IEEE.std_logic_unsigned.all;

use IEEE.std_logic_arith.all;

entity bell is

port(

clk:in std_logic; --50M时钟输入

reset_n:in std_logic; --复位信号输入

start_flag:in std_logic; --蜂鸣器开始相应信号

fm_time_over:out std_logic;

pwm_out:out std_logic; --蜂鸣器驱动脉冲

fm_20:out std_logic

);

end bell;

architecture bell_behave of bell is

signal count:std_logic_vector(14 downto 0);

signal pwm_signal:std_logic;

signal long_count:std_logic_vector(14 downto 0);

signal short_count:std_logic_vector(12 downto 0);

signal pwm_en:std_logic;

type state is(

prepare,--准备状态

start,--开始状态

stop

);

signal current_state:state;--一开始处于准备状态

begin

fm_20 <= pwm_en;

-- //****************************************************************************************************

-- // 模块名称:蜂鸣器驱动脉冲产生模块

-- // 功能描述:1KHz

-- //****************************************************************************************************

process(clk,reset_n)

begin

if(reset_n = '0')then

count <= "000000000000000";

pwm_signal <= '0';

elsif(clk'event and clk = '1')then--上升沿触发

if(count = "110000110101000")then

count <= "000000000000000";

pwm_signal <= not pwm_signal;

else

count <= count + '1';

end if;

end if;

end process;

-- //****************************************************************************************************

-- // 模块名称:蜂鸣器响应时间产生模块

-- // 功能描述:

-- //****************************************************************************************************

process(pwm_signal,reset_n)

begin

if(reset_n = '0')then

current_state <= prepare;

short_count <= "0000000000000";

long_count <= "000000000000000";

fm_time_over <= '0';

pwm_en <= '0';

elsif(pwm_signal'event and pwm_signal = '1')then--上升沿触发

case current_state is

when prepare=>

if(start_flag = '1')then

if(short_count = "1101101011000")then--5s

short_count <= "0000000000000";

current_state <= start;

else

short_count <= short_count + '1';

current_state <= prepare;

end if;

else

current_state <= prepare;

short_count <= "0000000000000";

long_count <= "000000000000000";

fm_time_over <= '0';

pwm_en <= '0';

end if;

when start=>

if(long_count = "100111000100000")then--20s

long_count <= "000000000000000";

pwm_en <= '0';

fm_time_over <= '1';

current_state <= stop;

else

current_state <= start;

long_count <= long_count + '1';

pwm_en <= '1';

fm_time_over <= '0';

end if;

when stop=>

pwm_en <= '0';

fm_time_over <= '1';

current_state <= prepare;

short_count <= "0000000000000";

long_count <= "000000000000000";

end case;

end if;

end process;

pwm_out <= pwm_en and pwm_signal;

end bell_behave;

 

实验操作

上电

接入5V电源,用配套的线,USB那端接电脑即可;

电源开关

按下电源开关

显示

数码管开始显示

显示的数码管为"0000"

右边的四个是显示当前输入的密码,从左到右分别是第一个到第四个密码

复位

按下复位按键,此时数码管清零0000;

电子锁自锁

仅有红灯亮着,表示电子锁锁住了

输入错误密码

正确密码"1111",例如输入错误密码"2222"

Key2用于选择输入密码数:0~9,选择好后按下key1按键,表示确定。

第一步:按下key1按键输入第一个密码输入完第一个密码后按下key1。

第二步:开始输入第二个密码,输入第二个密码,第二个密码输入完成后按下key1。

第三步:开始输入第三个密码,输入第三个密码,第三个密码输入完成后按下key1。

第四步:开始输入第四个密码,输入第四个密码,第四个密码输入完成后按下key1,输入完成;

这个过程的操作必须在5s内,否则就违时,蜂鸣器就会响20s。

完成后红色灯还是亮着的,绿色灯没有亮。

输入正确密码

输入正确密码"1111"

Key2用于选择输入密码数:0~9,选择好后按下key1按键,表示确定。

第一步:按下key1按键输入第一个密码,左边的数码管会显示1,输入完第一个密码后按下key1。

第二步:开始输入第二个密码,输入第二个密码,第二个密码输入完成后按下key1。

第三步:开始输入第三个密码,输入第三个密码,第三个密码输入完成后按下key1。

第四步:开始输入第四个密码,输入第四个密码,第四个密码输入完成后按下key1,输入完成;

这个过程的操作必须在5s内,否则就违时,蜂鸣器就会响20s。

完成后红色灯灭,绿色灯亮;

 

修改密码

只有在输入正确密码后,才能进行修改密码;

第一步:按下key1按键,ledD4亮,表示可以进行修改密码;

第二步:输入新密码,输入新密码与输入密码的过程一致,输入完成后,让左边的数码管显示"1",然后按下key3按键,ledD4灭,表示确定输入的新密码,FPGA就会将新的密码进行加载。

例如将新密码改为"2222"

输入过程红灯和绿灯是不显示的。

重新输入修改后的密码

输入新的正确密码"2222"

Key2用于选择输入密码数:0~9,选择好后按下key1按键,表示确定。

第一步:按下key1按键输入第一个密码,左边的数码管会显示1,输入完第一个密码后按下key1。

第二步:开始输入第二个密码,输入第二个密码,第二个密码输入完成后按下key1。

第三步:开始输入第三个密码,输入第三个密码,第三个密码输入完成后按下key1。

第四步:开始输入第四个密码,输入第四个密码,第四个密码输入完成后按下key1;

这个过程的操作必须在5s内,否则就违时,蜂鸣器就会响20s。

完成后红色灯灭,绿色灯亮;

 

输入密码时间超过5s

如果按下密码选择按键key1,然后在5s内没有输入好正确的密码,则蜂鸣器会响起。

蜂鸣器响应20s

在违时后蜂鸣器会相应20s,且这个时间内是不能进行密码输入的;

 

 

 

大西瓜FPGA-->https://daxiguafpga.taobao.com

配套开发板:https://item.taobao.com/item.htm?spm=a1z10.1-c.w4004-24211932856.3.489d7241aCjspB&id=633897209972

博客资料、代码、图片、文字等属大西瓜FPGA所有,切勿用于商业! 若引用资料、代码、图片、文字等等请注明出处,谢谢!

   

每日推送不同科技解读,原创深耕解读当下科技,敬请关注微信公众号"科乎"。

posted @ 2022-02-20 17:37  logic3  阅读(1324)  评论(0编辑  收藏  举报