最近在学习FPGA,就试着写了个按键扫描的程序。虽说有过基于单片机的按键扫描处理经验,对于按键的处理还是有一些概念。
但是单片机程序的编写通常都采用C写,也有用汇编,而FPGA却是采用VHDL或者Verilog这种硬件描述语言来编写。初次利用VHDL编写
控制程序,最开始就有点反应不过来了。采用VHDL语言编写程序与用C语言编写,在思维上会有很大的不一样,因为C程序时顺序执行的,而VHDL语言
各个进程之间是并行执行的,这就会要考虑到时序方面的问题,这正也合乎了硬件工作实际过程,毕竟各个功能模块之间既独立又相关的嘛。
说回基于FPGA的按键扫描处理的问题,通常对按键的处理都要进行延时去抖,以避免按键按下产生的机械抖动等因素影响对按键状态的正确判决。
而且除了要扫描判断按键是否按下,也要扫描判断按键是否弹开(否则一次按键按下如果时间相对长一些,那么程序很容易会误认为连续多次按下)。
基于以上分析,下面是我整理了一下用VHDL语言编写的扫描代码,程序实现按键单击,双击,长按的判断处理。(程序中时钟对应50MHZ,根据不同的主时钟对分频应做相应的修改)
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_unsigned.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity key is
port(key_state:in BIT;--按键转态,1->按下,0->未按下
clk:in std_logic;
mode1,mode2:out integer range 0 to 2;
q:out integer range 0 to 2
);
end key;
architecture Behavioral of key is
signal cntDiv: std_logic_vector(28 downto 0);
signal key_count,up_key:integer range 0 to 200000;
signal twit_count:integer range 0 to 3;--用于判断是否为双击状态
signal flag_state:integer range 0 to 1;--用于判断是否有按键按下以及按下一次还是连续两次按下
type state is (short_key,long_key,twis_key);--no_key,
signal pr_state:state;
--signal LONG_KEY,TWICE_KEY:integer range 0 to 1000;
begin
process(clk)
begin
if(clk‘event and clk = ‘1‘)then
cntDiv <= cntDiv + ‘1‘;
end if;
end process;
process(cntDiv(7),key_state)
variable flag1,flag2:integer range 0 to 2;------------用于区分短按以及长按的各自不同功能
------------flag1=0/1 => 功能1/功能2;
------------flag2=0/1 => 功能3/功能4;
begin
if(cntDiv(7)‘event and cntDiv(7) = ‘1‘)then
if(key_state = ‘1‘)then
key_count <= key_count +1;
up_key <= 0;
flag_state <= 1;
else
if(key_count > 20 and key_count < 50000)then
twit_count <= twit_count + 1; --判断是否长按的标志
key_count <= 0;
elsif(key_count > 50000)then --------------长按
pr_state <= long_key;
key_count <= 0;
up_key <= 0;
flag_state <= 0;
--////////////根据设计需要添加的代码//////////////////
--代码......................
------------------------------------------------
else
key_count <= 0;
end if;
-------双击,up_key为按键跳起至下一次按下持续时间
if(up_key > 20 and up_key < 50000 and twit_count = 2 )then pr_state <=twis_key;
flag_state <= 0;
up_key <= 0;
twit_count <= 0;
flag2 := flag2 +1;
if(flag2 = 2)then flag2 :=0;
end if;
mode2 <= flag2;
--////////////根据设计需要添加的代码//////////////////
--代码......................
------------------------------------------------
end if;
if(up_key > 50000 and twit_count = 1)then --短按
pr_state <= short_key;
flag_state <= 0;
up_key <= 0;
twit_count <= 0;
flag1 := flag1 +1;
if(flag1 = 2)then flag1 :=0;end if;
--////////////根据设计需要添加的代码//////////////////
--代码......................
------------------------------------------------
end if;
if(flag_state = 1)then
up_key <= up_key + 1;
end if;
end if;
end if;
end process;
process(pr_state)
--variable flag1,flag2:integer range 0 to 2;
begin
case pr_state is
when short_key => q <= 0;------短按返回结果标志
when long_key => q <= 1;------长按结果标志
when twis_key => q <= 2;------双击结果标志
end case;
end process;
end Behavioral;