LIBRARY IEEE; 
USE IEEE.STD_LOGIC_1164.ALL; 
USE IEEE.STD_LOGIC_ARITH.ALL ; 
USE IEEE.STD_LOGIC_UNSIGNED.ALL ; 
ENTITY KEYBOARD IS
PORT (CLK_1K: IN STD_LOGIC ; 
 --系统原始时钟脉冲(1 kHz)
 KEY_IN: IN STD_LOGIC_VECTOR (2 DOWNTO 0); 
 --按键输入
 CLK_SCAN: OUT STD_LOGIC_VECTOR (3 DOWNTO 0) ;
 --( 仿真时用)键盘扫描序列
 DATA_N: OUT STD_LOGIC_VECTOR(3 DOWNTO 0) ; 
 --数字输出
 DATA_F: OUT STD_LOGIC_VECTOR(3 DOWNTO 0) ; 
 --功能输出
 FLAG_N: OUT STD_LOGIC ; --数字输出标志
 FLAG_F: OUT STD_LOGIC ; --功能输出标志
 CLK_CTR: OUT STD_LOGIC; --控制电路工作时钟信号
 CLK_DEBOUNCE: OUT STD_LOGIC);
 --(仿真时用)去抖电路工作时钟信号
END ENTITY KEYBOARD ; 
ARCHITECTURE ART OF KEYBOARD IS
 COMPONENT DEBOUNCING IS
PORT(D_IN: IN STD_LOGIC ; 
CLK: IN STD_LOGIC ; 
D_OUT: OUT STD_LOGIC ) ; 
 END COMPONENT DEBOUNCING; 
 SIGNAL CLK: STD_LOGIC ; --电路工作时钟脉冲
 SIGNAL C_KEYBOARD: STD_LOGIC_VECTOR(1 DOWNTO 0); 
 --键扫信号“00-01-10-11”寄存器
 SIGNAL C_DEBOUNCE: STD_LOGIC ; 
 --去抖时钟信号
 SIGNAL C: STD_LOGIC_VECTOR(2 DOWNTO 0) ; 
 --键盘输入去抖后的寄存器
 SIGNAL N , F: STD_LOGIC_VECTOR(3 DOWNTO 0) ; 
 --数字、功能按键译码值的寄存器
 SIGNAL FN , FF: STD_LOGIC ; 
 --数字、功能按键标志值数字、功能按键
 SIGNAL SEL: STD_LOGIC_VECTOR (3 DOWNTO 0) ; 
 BEGIN
-- 内部连接
DATA_N <= N ; 
DATA_F <= F ; 
FLAG_N <= FN ; 
FLAG_F <= FF ; 
CLK_CTR <= CLK ; 
 
 --扫描信号发生器
COUNTER : BLOCK IS
SIGNAL Q: STD_LOGIC_VECTOR(5 DOWNTO 0); 
SIGNAL SEL: STD_LOGIC_VECTOR (3 DOWNTO 0); 
 --1110-1101-1011-0111 
 BEGIN
PROCESS (CLK_1K) IS 
 BEGIN
 IF CLK_1K'EVENT AND CLK_1K ='1' THEN
 Q <= Q+1; 
 END IF; 
C_DEBOUNCE <= Q(2) ; --去抖时钟信号, 大约 125 Hz 
C_KEYBOARD <= Q(6 DOWNTO 5) ;
-- 产生键扫信号***“00-01-10-11”, 大约 16 Hz
C_DEBOUNCE <= Q(1) ; --仿真时用
C_KEYBOARD <= Q(5 DOWNTO 4) ; --仿真时用
 CLK <= Q(0) ; 
END PROCESS; 
CLK_DEBOUNCE<=C_DEBOUNCE; 
SEL <= "1110" WHEN C_KEYBOARD=0 ELSE
"1101" WHEN C_KEYBOARD=1 ELSE
"1011" WHEN C_KEYBOARD=2 ELSE
"0111" WHEN C_KEYBOARD=3 ELSE
"1111"; 
CLK_SCAN <= SEL ; 
 END BLOCK COUNTER ; 
 --键盘去抖
DEBOUNUING : BLOCK IS
 BEGIN
U1: DEBOUNCING PORT MAP (D_IN => KEY_IN(0) , D_OUT => C(0), 
CLK => C_DEBOUNCE); 
U2: DEBOUNCING PORT MAP (D_IN => KEY_IN(1) , D_OUT => C(1), 
CLK => C_DEBOUNCE); 
U3: DEBOUNCING PORT MAP (D_IN => KEY_IN(2) , D_OUT => C(2), 
CLK => C_DEBOUNCE ); 
END BLOCK DEBOUNUING ; 
 --键盘译码
 KEY_DECODER : BLOCK 
SIGNAL Z : STD_LOGIC_VECTOR(4 DOWNTO 0) ; 
 --按键位置
BEGIN
PROCESS(CLK)
 BEGIN
 Z <= C_KEYBOARD & C ; 
 IF CLK'EVENT AND CLK = '1' THEN
 CASE Z IS
 WHEN "11101" => N <= "0000" ; --0
 WHEN "00011" => N <= "0001" ; --1
 WHEN "00101" => N <= "0010" ; --2
 WHEN "00110" => N <= "0011" ; --3
 WHEN "01011" => N <= "0100" ; --4
 WHEN "01101" => N <= "0101" ; --5
 WHEN "01110" => N <= "0110" ; --6
 WHEN "10011" => N <= "0111" ; --7
 WHEN "10101" => N <= "1000" ; --8
 WHEN "10110" => N <= "1001" ; --9
 WHEN OTHERS => N <= "1111" ; 
END CASE ; 
 END IF ; 
IF CLK'EVENT AND CLK = '1' THEN
CASE Z IS
 WHEN "11011" => F <= "0100" ; --*_LOCK
 WHEN "11110" => F <= "0001" ; --#_UNLOCK
 WHEN OTHERS => F <= "1000" ; 
END CASE ; 
 END IF ; 
 END PROCESS ; 
FN <= NOT ( N(3) AND N(2) AND N(1) AND N(0) ) ; 
FF <= F(2) OR F(0) ; 
 END BLOCK KEY_DECODER ; 
END ARCHITECTURE ART;