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));--接绿色led,141引脚 password_no <= not ((password_no_temp) and (not password_set));--接红色led,142引脚
-- //**************************************************************************************************** -- // 模块名称:数码管显示数字选择模块 -- // 功能描述: -- //**************************************************************************************************** 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所有,切勿用于商业! 若引用资料、代码、图片、文字等等请注明出处,谢谢!
每日推送不同科技解读,原创深耕解读当下科技,敬请关注微信公众号"科乎"。