在设计中,利用VHDL硬件描述语言在FPGA芯片上实现键盘接口设计并利用仿真FPGA软件进行仿真,主要解决了三个问题:一是如何检测是否有按键按下并防止采集到干扰信号;二是在按键闭合时如何防止抖动;三是如何判断为哪一个按键位动作,并对其进行译码。
分为四个模块,分频模块,译码模块,键盘扫描模块,键值确定模块,
分频模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY FENPING IS
PORT(
CLK:IN STD_LOGIC;
CLK_200:OUT STD_LOGIC;
CLK_1K:OUT STD_LOGIC;
CLK_40K:OUT STD_LOGIC
);
END ENTITY;
ARCHITECTURE ART OF FENPING IS
SIGNAL COUNT0:INTEGER RANGE 0 TO 1249;
SIGNAL COUNT1:INTEGER RANGE 0 TO 49999;
SIGNAL COUNT2:INTEGER RANGE 0 TO 249999;
BEGIN
PROCESS(CLK)IS
BEGIN
IF(CLK'EVENT AND CLK='1')THEN
IF(COUNT0=1249)THEN COUNT0<=0;
ELSE COUNT0<=COUNT0+1;
END IF;
IF(COUNT1=49999)THEN COUNT1<=0;
ELSE COUNT1<=COUNT1+1;
END IF;
IF(COUNT2=249999)THEN COUNT2<=0;
ELSE COUNT2<=COUNT2+1;
END IF;
END IF;
END PROCESS;
PROCESS(COUNT0)IS
BEGIN
IF(COUNT0>=625)THEN CLK_40K<='1';
ELSE CLK_40K<='0';
END IF;
END PROCESS;
PROCESS(COUNT1)IS
BEGIN
IF(COUNT1>=25000)THEN CLK_1K<='1';
ELSE CLK_1K<='0';
END IF;
END PROCESS;
PROCESS(COUNT2)IS
BEGIN
IF(COUNT2>=125000)THEN CLK_200<='1';
ELSE CLK_200<='0';
END IF;
END PROCESS;
END ARCHITECTURE;
产生200HZ,1KHZ,40KHZ三中频率
译码模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY YIMA IS
PORT(
TMP:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
DIS:OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE ART OF YIMA IS
BEGIN
PROCESS(TMP)IS
BEGIN
CASE(TMP)IS
WHEN"0000"=>DIS<="00111111";
WHEN"0001"=>DIS<="00000110";
WHEN"0010"=>DIS<="01011011";
WHEN"0011"=>DIS<="01001111";
WHEN"0100"=>DIS<="01100110";
WHEN"0101"=>DIS<="01101101";
WHEN"0110"=>DIS<="01111101";
WHEN"0111"=>DIS<="00000111";
WHEN"1000"=>DIS<="01111111";
WHEN"1001"=>DIS<="01101111";
WHEN"1010"=>DIS<="01110111";
WHEN"1011"=>DIS<="01111100";
WHEN"1100"=>DIS<="00111001";
WHEN"1101"=>DIS<="01011110";
WHEN"1110"=>DIS<="01111001";
WHEN"1111"=>DIS<="01110001";
WHEN OTHERS=>DIS<="00000000";
END CASE;
END PROCESS;
END ARCHITECTURE;
得到键值后,译成数码管显示的键值,由于只有一个数码管,所以不存在位扫描。
键盘扫描模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY KEY_SCAN IS
PORT(
CLK_200:IN STD_LOGIC;
KEY_LIE:OUT STD_LOGIC_VECTOR(3 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE ART OF KEY_SCAN IS
SIGNAL CURRENT_STATE,NEXT_STATE:STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
PROCESS(CLK_200)IS
BEGIN
IF(CLK_200'EVENT AND CLK_200='1')THEN
CURRENT_STATE<=NEXT_STATE;
END IF;
END PROCESS;
PROCESS(CURRENT_STATE)IS
BEGIN
CASE CURRENT_STATE IS
WHEN"1110"=>NEXT_STATE<="1101";
WHEN"1101"=>NEXT_STATE<="1011";
WHEN"1011"=>NEXT_STATE<="0111";
WHEN"0111"=>NEXT_STATE<="1110";
WHEN OTHERS=>NEXT_STATE<="1110";
END CASE;
END PROCESS;
KEY_LIE<=CURRENT_STATE;
END ARCHITECTURE;
键盘扫描的思路是对输出列信号四位轮流输出低电平,检测输入行信号四位是否有低电平,有低电平说明有键码按下,再根据行列的矢量值,判断到底是哪一位按下。
键值确定模块
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY JIANPAN1 IS
PORT(
CLK:IN STD_LOGIC;
KEY_HANG:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
KEY_LIE:BUFFER STD_LOGIC_VECTOR(3 DOWNTO 0);
DIS:OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE ART OF JIANPAN1 IS
COMPONENT FENPING IS
PORT(
CLK:IN STD_LOGIC;
CLK_200:OUT STD_LOGIC;
CLK_1K:OUT STD_LOGIC;
CLK_40K:OUT STD_LOGIC
);
END COMPONENT;
COMPONENT YIMA IS
PORT(
TMP:IN STD_LOGIC_VECTOR(3 DOWNTO 0);
DIS:OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
);
END COMPONENT;
COMPONENT KEY_SCAN IS
PORT(
CLK_200:IN STD_LOGIC;
KEY_LIE:OUT STD_LOGIC_VECTOR(3 DOWNTO 0)
);
END COMPONENT;
SIGNAL keyvalue:STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL KEY_CODE:STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL TMP:STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL CLK_200,CLK_1K,CLK_40K,INT,temp_pressed:STD_LOGIC;
BEGIN
U1:FENPING PORT MAP(CLK,CLK_200,CLK_1K,CLK_40K);
U2:KEY_SCAN PORT MAP(CLK_200,KEY_LIE);
U3:YIMA PORT MAP(TMP,DIS);
INT<=NOT(KEY_HANG(0)AND KEY_HANG(1)AND KEY_HANG(2)AND KEY_HANG(3));
KEY_CODE<=KEY_HANG&KEY_LIE;
PROCESS(CLK_40K)IS
BEGIN
IF(INT='1')THEN
IF(CLK_40K'EVENT AND CLK_40K='1')THEN
IF(INT='1')THEN
CASE KEY_CODE IS
WHEN"11101110"=>keyvalue<=CONV_STD_LOGIC_VECTOR(0,4);
temp_pressed<='1';
WHEN"11101101" =>keyvalue<=CONV_STD_LOGIC_VECTOR(1,4);
temp_pressed<='1';
WHEN"11101011" =>keyvalue<=CONV_STD_LOGIC_VECTOR(2,4);
temp_pressed<='1';
WHEN"11100111" =>keyvalue<=CONV_STD_LOGIC_VECTOR(3,4);
temp_pressed<='1';
WHEN"11011110" =>keyvalue<=CONV_STD_LOGIC_VECTOR(4,4);
temp_pressed<='1';
WHEN"11011101" =>keyvalue<=CONV_STD_LOGIC_VECTOR(5,4);
temp_pressed<='1';
WHEN"11011011" =>keyvalue<=CONV_STD_LOGIC_VECTOR(6,4);
temp_pressed<='1';
WHEN"11010111" =>keyvalue<=CONV_STD_LOGIC_VECTOR(7,4);
temp_pressed<='1';
WHEN"10111110" =>keyvalue<=CONV_STD_LOGIC_VECTOR(8,4);
temp_pressed<='1';
WHEN"10111101" =>keyvalue<=CONV_STD_LOGIC_VECTOR(9,4);
temp_pressed<='1';
WHEN"10111011" =>keyvalue<=CONV_STD_LOGIC_VECTOR(10,4);
temp_pressed<='1';
WHEN"10110111" =>keyvalue<=CONV_STD_LOGIC_VECTOR(11,4);
temp_pressed<='1';
WHEN"01111110" =>keyvalue<=CONV_STD_LOGIC_VECTOR(12,4);
temp_pressed<='1';
WHEN"01111101" =>keyvalue<=CONV_STD_LOGIC_VECTOR(13,4);
temp_pressed<='1';
WHEN"01111011" =>keyvalue<=CONV_STD_LOGIC_VECTOR(14,4);
temp_pressed<='1';
WHEN"01110111" =>keyvalue<=CONV_STD_LOGIC_VECTOR(15,4);
temp_pressed<='1';
WHEN OTHERS =>
temp_pressed<='0';
END CASE;
END IF;
END IF;
END IF;
END PROCESS;
PROCESS(CLK_1K)IS
BEGIN
IF(temp_pressed='1')THEN
IF(CLK_1K'EVENT AND CLK_1K='1')THEN
TMP<=keyvalue;
END IF;
END IF;
END PROCESS;
END ARCHITECTURE;
在动态输入列信号,扫描行信号,得到键值。
本实验的关键在于键盘检测的思想,对行赋值,检测列值,关于消抖程序,不太明白,好像也没涉及到。