📄 keyb.vhd
字号:
---------------------------------------------------------------------------
-- --
-- FPGA IMPLEMENTATION OF AN ELECTRONIC LOCK --
-- Gabriele Guarnieri --
-- 17 March 2004 --
-- --
---------------------------------------------------------------------------
library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_ARITH.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;-- Uncomment the following lines to use the declarations that are-- provided for instantiating Xilinx primitive components.--library UNISIM;--use UNISIM.VComponents.all;entity keyb is Port ( clk_50k : in std_logic; -- Master clock row : out std_logic_vector(3 downto 0); -- Keyboard rows col : in std_logic_vector(2 downto 0); -- Keyboard columns flash_a : out std_logic_vector(17 downto 0); -- Flash address bus flash_d : inout std_logic_vector(7 downto 0); -- Flash data bus, LED flash_cen : out std_logic; -- Flash /CE flash_oen : inout std_logic; -- Flash /OE flash_wen2 : out std_logic; -- Flash /WE flash_rstn : out std_logic; -- Flash /RESET enable : inout std_logic); -- Global asynchronous resetend keyb;architecture keyb_arch of keyb is
-- Internal 100 Hz clock signal clk_100: std_logic;
-- Keyboard registers signal col_dummy: std_logic_vector(2 downto 0);
signal row_save: std_logic_vector(1 downto 0); signal col_save: std_logic_vector(2 downto 0); -- Keyboard decoder signal keyval: std_logic_vector(3 downto 0); signal key_isdigit, key_isstar, key_ishash, key_err: std_logic; -- Keyboard to binary converter type k2b_state_type is (k2b_idle, k2b_keydown, k2b_keyup); signal k2b_state, next_k2b_state: k2b_state_type; signal res_ctr: std_logic_vector(9 downto 0); signal value: std_logic_vector(23 downto 0); signal count: std_logic_vector(2 downto 0); signal res_ctr_load, k2b_ce, keyb_reset: std_logic; -- Main control process type mp_state_type is (mp_waituser, mp_waitpass, mp_err, mp_open, mp_waituser2, mp_waitpass2, mp_changepass); signal mp_state, next_mp_state: mp_state_type; signal err_ctr: std_logic_vector(9 downto 0); signal led_ctr: std_logic_vector(6 downto 0); signal user: std_logic_vector(7 downto 0); signal pass, pass_m: std_logic_vector(23 downto 0); signal flash_read, flash_write, save_user, save_pass, err_ctr_load, led_ctr_load: std_logic; -- Flash read type fr_state_type is (fr_idle, fr_search, fr_readpass_23_16, fr_readpass_15_8, fr_readpass_7_0, fr_end); signal fr_state, next_fr_state: fr_state_type; signal flash_abufr, next_flash_abufr: std_logic_vector(17 downto 0);
signal save_pass_m: std_logic;
-- Flash write type fw_state_type is (fw_idle, fw_search, fw_byte1, fw_byte2, fw_byte3, fw_byte4, fw_end); signal fw_state, next_fw_state: fw_state_type; signal flash_abufw, next_flash_abufw: std_logic_vector(17 downto 0); signal flash_dbuf: std_logic_vector(7 downto 0); signal fw_bytectr, next_fw_bytectr: std_logic_vector(1 downto 0);
signal flash_wen: std_logic; -- Led signal led : std_logic_vector(6 downto 0); -- Pullup resistor component declaration component PULLUP port (O: out std_logic); end component; -- Pulldown resistor component declaration component PULLDOWN port (O: out std_logic); end component;begin---------------------------------------------------------------------------
-- Clock divider:-- Divides the 50 KHz master clock "clk_50k" by 500 and outputs a 100 Hz
-- clock to the "clk_100" signal.---------------------------------------------------------------------------
process(clk_50k) variable clk_ctr: std_logic_vector(7 downto 0);begin if rising_edge(clk_50k) then if clk_ctr = 249 then clk_ctr := (others => '0'); clk_100 <= not clk_100; else clk_ctr := clk_ctr+1; end if; end if;end process;
---------------------------------------------------------------------------
-- Keyboard interface:
-- Scans the keyboard rows and outputs the current key configuration-- to the "row_save" and "col_save" signals.---------------------------------------------------------------------------
-- Attach pulldown resistors to the columnscol_dummy <= col;R_col_2: PULLDOWN port map (O => col_dummy(2));R_col_1: PULLDOWN port map (O => col_dummy(1));R_col_0: PULLDOWN port map (O => col_dummy(0));
process(clk_100) variable row_count: std_logic_vector(1 downto 0);begin -- Row scan if rising_edge(clk_100) then row_count := row_count+1; end if; -- Row decode
-- Inactive rows are set to 'Z' to prevent short circuits in case the
-- user presses multiple keys on the same column case row_count is when "00" => row <= "1ZZZ"; when "01" => row <= "Z1ZZ"; when "10" => row <= "ZZ1Z"; when "11" => row <= "ZZZ1"; when others => NULL; end case; -- Save the current key configuration until the key is released if falling_edge(clk_100) then if col_dummy /= "000" or row_count = row_save then row_save <= row_count; col_save <= col_dummy; end if; end if;end process;
---------------------------------------------------------------------------
-- Keyboard decoder:-- Converts the output of the keyboard interface to decimal value "keyval".
-- Generates the control signals "key_isdigit" (digit pressed),
-- "key_isstar" (star), "key_ishash" (hash) and "key_err" (multiple keys
-- pressed).
---------------------------------------------------------------------------
process(row_save, col_save) variable rowcol: std_logic_vector(4 downto 0);begin rowcol := row_save & col_save; keyval <= (others => 'X'); key_isdigit <= '1'; key_isstar <= '0'; key_ishash <= '0'; key_err <= '0'; case rowcol is when "00100" => keyval <= "0001"; -- 1 when "00010" => keyval <= "0010"; -- 2 when "00001" => keyval <= "0011"; -- 3 when "01100" => keyval <= "0100"; -- 4 when "01010" => keyval <= "0101"; -- 5 when "01001" => keyval <= "0110"; -- 6 when "10100" => keyval <= "0111"; -- 7 when "10010" => keyval <= "1000"; -- 8 when "10001" => keyval <= "1001"; -- 9 when "11100" => key_isdigit <= '0'; key_isstar <= '1'; -- * when "11010" => keyval <= "0000"; -- 0 when "11001" => key_isdigit <= '0'; key_ishash <= '1'; -- # when "00000" | "01000" | "10000" | "11000" => key_isdigit <= '0'; -- Off when others => key_isdigit <= '0'; key_err <= '1'; -- Multiple keys pressed end case;end process;
---------------------------------------------------------------------------
-- Keyboard to BCD conversion FSM:-- Builds the BCD code for the current key sequence by shifting the digits
-- into the "value" register. The length of the sequence is stored in the
-- "count" counter. If multiple keys are pressed, only the first one is
-- stored. The system is reset after 10 second of idle time. The # key
-- clears the registers
---------------------------------------------------------------------------
process(clk_100, enable)begin if enable = '0' then k2b_state <= k2b_idle; value <= (others => '1'); count <= (others => '0'); elsif rising_edge(clk_100) then -- State change
k2b_state <= next_k2b_state;
-- Timeout counter if res_ctr_load = '1' then res_ctr <= (others => '1'); elsif res_ctr /= 0 then res_ctr <= res_ctr - 1; end if;
if k2b_ce = '1' then -- Store the current key and increment the counter
value <= value(19 downto 0) & keyval; count <= count + 1;
elsif key_ishash = '1' or keyb_reset = '1' then
-- Clear the registers
value <= (others => '1'); count <= (others => '0'); end if; end if;end process; process(k2b_state, key_isdigit, key_err, key_ishash, res_ctr)begin -- Set the default values
res_ctr_load <= '0'; k2b_ce <= '0'; enable <= 'Z'; next_k2b_state <= k2b_state; if k2b_state = k2b_idle then
-- Idle state: no keyboard activity if key_isdigit = '1' then
-- User presses a key: start a new sequence and load the timeout counter next_k2b_state <= k2b_keydown; k2b_ce <= '1'; res_ctr_load <= '1'; end if; elsif k2b_state = k2b_keydown then
-- User is holding down the key if key_isdigit = '0' and key_err = '0' then
-- User has released the key next_k2b_state <= k2b_keyup; end if; elsif k2b_state = k2b_keyup then
-- Same as k2b_idle, except that the timeout counter is running if res_ctr = 0 then
-- 10 seconds timeout => system reset enable <= '0'; end if; if key_isdigit = '1' then
next_k2b_state <= k2b_keydown; k2b_ce <= '1'; res_ctr_load <= '1'; end if; else -- Invalid state => system reset
enable <= '0'; end if;end process;
---------------------------------------------------------------------------
-- Led output:
-- Calculates the pattern for the 7-segment display from the state of the
-- main control process
---------------------------------------------------------------------------
process(mp_state, err_ctr)begin case mp_state is when mp_waituser | mp_waituser2 => -- Waiting for the username => "U"
led <= "0110111"; when mp_waitpass | mp_waitpass2 =>
-- Waiting for the password => "P" led <= "1111100"; when mp_err =>
-- Nonexistent user or wrong password => blinking "E" led <= (1 => '0', 4 => '0', others => err_ctr(4)); when mp_open =>
-- Valid password, door open => "O" led <= "1110111"; when mp_changepass =>
-- Password changed, writing to Flash => "F" led <= "1101100"; when others =>
-- Invalid state => DCC led <= (others => 'X'); end case;end process;---------------------------------------------------------------------------
-- Led-Flash multiplexer:
-- Shares the Flash data bus with the 7-segment display
---------------------------------------------------------------------------
R_flash_cen: PULLUP port map (O => flash_cen);R_flash_oen: PULLUP port map (O => flash_oen);R_flash_rstn: PULLUP port map (O => flash_rstn);
process(flash_oen, flash_wen, flash_dbuf, led)begin flash_wen2 <= '1';
if flash_oen = '0' then
-- Flash read => Set the bus to 'Z' flash_d <= (others => 'Z');
elsif flash_wen = '0' then
-- Flash write => Output the data and the clock flash_d <= flash_dbuf;
flash_wen2 <= not clk_50k; else -- No flash activity => output the LED pattern
flash_d(7) <= led(0); flash_d(0) <= led(1); flash_d(6) <= led(2); flash_d(5) <= led(3); flash_d(2) <= led(4); flash_d(4) <= led(5); flash_d(3) <= led(6); flash_d(1) <= 'Z';
end if;end process;---------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -