FPGA学习心得——矩阵键盘

1、行列式键盘概述

为了减少键盘与单片机接口时所占用I/O口线的数目,在键数较多时,通常都将键盘排列成行列矩阵式,行列式键盘又叫矩阵式键盘。用带有I/O口的线组成行列结构,按键设置在行列的交点上。例如用2*2的行列结构可以构成4个键的键盘,4*4的行列结构可以构成有16个键的键盘。这样,当按键数量平方增长时,I/O口线只是线性增长,这样就可以节省I/O口线。

2、行列式键盘原理

教研室已有薄膜矩阵键盘,其实物图如图所示。

其电路原理图如下图所示。

按键设置在行列线交叉点,行、列线分别连接到按键开关的两端。列线通过上拉电阻接+5V的电压,即列线的输出被钳位到高电平状态。行线与按键的一个引脚相连,列线与按键的另一个引脚相连。判断键盘中有无按键按下是通过行线送入扫描信号,然后从列线读取状态得到的。其方法是依次行线送低电平,检查列线的输入。如果列线信号全为高电平,则代表低电平信号所在的行中无按键按下;如果列线有输入为低电平,则低电平信号所在的行和出现低电平的列的交点处有按键按下。

设行扫描信号为keydrv3~keydrv0,列线按键输入信号keyin3~keyin0与按键位置的关系如下表所示。

由行列式键盘的原理可以知道,要正确地完成按键输入工作必须有按键扫描电路产生keydrv3~keydrv0信号。同时还必须有按键译码电路从keydrv3~keydrv0信号和keyin3~keyin0信号中译码出按键的键值。此外,一般还需要一个按键发生标志信号用于和其他模块接口,通知其它模块键盘上有按键动作发生,并可以从键盘模块中读取按键键值。由于各个模块需要的时钟频率是不一样的,因此时钟产生模块就是用于产生各个模块需要的时钟信号。因此得到键盘接口电路的结构如图2所示。

图2 键盘接口电路结构图

行列式键盘电路的FPGA实现主要解决三个问题,一是如何检测是否有按键按下并防止采集到干扰信号;二是在按键闭合时如何防止抖动;三是如何判断为哪一个按键位动作,并对其进行译码。因此,为了解决这些问题,程序中使用不同的进程分别实现键盘扫描信号的产生、键盘去抖以及键盘的译码。

3、源程序

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    08:46:57 07/31/2012 
-- Design Name: 
-- Module Name:    MatrixKeyboard - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity MatrixKeyboard is
    Port ( Clk 		: in  	STD_LOGIC;
			  Reset		: in		STD_LOGIC;
           KeyIn	 	: in  	STD_LOGIC_VECTOR (3 downto 0);
			  KeyScan 	: out	   STD_LOGIC_VECTOR (3 downto 0);
           LED 		: out  	STD_LOGIC_VECTOR (3 downto 0)
			  );
end MatrixKeyboard;

architecture Behavioral of MatrixKeyboard is

Signal Clk_scan	:	STD_LOGIC	:=		'0';
Signal Clk_5ms		:	STD_LOGIC	:=		'0';
Signal Clk_2ms		:	STD_LOGIC	:=		'0';
Signal Key_Scan	:  STD_LOGIC_VECTOR(3 downto 0);
Signal Key_Decode	: 	STD_LOGIC_VECTOR(7 downto 0);

Type State_Key is(st_key1,st_key2,st_key3,st_key4);
Signal Current_Key : State_Key := st_key1;

Type State_Scan is(st_scan1,st_scan2,st_scan3,st_scan4);
Signal Current_Scan : State_Scan := st_scan1;

begin

	Proc_Clk_5ms : process(Clk)
	variable cnt_clk : integer range 0 to 250000 := 0;
	begin
		if(rising_edge(Clk)) then
			if(cnt_clk < 125000) then	
				cnt_clk 	:= cnt_clk + 1;
				Clk_scan	<= '0';
			elsif(cnt_clk < 249999) then
				cnt_clk 	:= cnt_clk + 1;
				Clk_scan	<= '1';
			else
				cnt_clk 	:= 0;
			end if;
			Clk_5ms	<= Clk_scan;
		end if;
	end process Proc_Clk_5ms;
	
	Proc_Clk_2ms : process(Clk)
	variable cnt_clk : integer range 0 to 100000 := 0;
	begin
		if(rising_edge(Clk)) then
			if(cnt_clk < 50000) then	
				cnt_clk 	:= cnt_clk + 1;
				Clk_2ms	<= '0';
			elsif(cnt_clk < 99999) then
				cnt_clk 	:= cnt_clk + 1;
				Clk_2ms	<= '1';
			else
				cnt_clk 	:= 0;
			end if;
		end if;
	end process Proc_Clk_2ms;
	
	
	Proc_Scan:process(Clk_5ms)
	begin
		if(rising_edge(Clk_5ms)) then
			case Current_Scan is
				when st_scan1 =>
					Key_Scan <= "1110";
					Current_Scan <= st_scan2;
				when st_scan2 =>
					Key_Scan <= "1101";
					Current_Scan <= st_scan3;
				when st_scan3 =>
					Key_Scan <= "1011";
					Current_Scan <= st_scan4;
				when st_scan4 =>
					Key_Scan <= "0111";
					Current_Scan <= st_scan1;
			end case;
		end if;
		
	end process Proc_Scan;
	
	KeyScan <= Key_Scan;
	Key_Decode <= Key_Scan & Keyin;
	
	Proc_Keyboard:process(Clk_2ms,Reset)
	variable cnt_btn : integer range 0 to 50000 := 0;
	begin
		if(Reset = '1') then
			LED	<=	x"1";
			Current_Key	<= st_key1;
		elsif(falling_edge(Clk_2ms)) then
			case Current_Key is
				when st_key1 =>				--Check whether any keys are pressed
					if((Keyin and "1111") = "1111") then 
						Current_Key <= st_key1;
					else
						Current_Key <= st_key2;
					end if;
				when st_key2 =>				--keys debouncing
					if((Keyin and "1111") = "1111") then 
						Current_Key <= st_key1;
					else
						case Key_Decode is
							when "11101110" => LED <= "0001";
							when "11101101" => LED <= "0010";
							when "11101011" => LED <= "0011";
							when "11100111" => LED <= "1010";
							when "11011110" => LED <= "0100";
							when "11011101" => LED <= "0101";
							when "11011011" => LED <= "0110";
							when "11010111" => LED <= "1011";
							when "10111110" => LED <= "0111";
							when "10111101" => LED <= "1000";
							when "10111011" => LED <= "1001";
							when "10110111" => LED <= "1100";
							when "01111110" => LED <= "1110";
							when "01111101" => LED <= "0000";
							when "01111011" => LED <= "1111";
							when "01110111" => LED <= "1101";							                                     when others     => null;     
						end case;
					end if;
						Current_Key <= st_key3;
				when st_key3 =>			--Check whether the pressed keys are released
					if((Keyin and "1111") /= "1111") then 
						Current_Key <= st_key3;
					else
						Current_Key <= st_key4;
					end if;
				when st_key4 =>				--keys debouncing
					if((Keyin and "1111") /= "1111") then 
						Current_Key <= st_key3;
					else
						LED	<=	x"0";
						Current_Key <= st_key1;
					end if;
			end case;
		end if;
	end process Proc_Keyboard;

end Behavioral;

你可能感兴趣的:(FPGA)