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所有,切勿用於商業! 若引用資料、代碼、圖片、文字等等請注明出處,謝謝!
每日推送不同科技解讀,原創深耕解讀當下科技,敬請關注微信公眾號"科乎"。