如何计算FPGA斯巴达板上的按键数 [英] How to count pressed keys on FPGA spartan board

查看:99
本文介绍了如何计算FPGA斯巴达板上的按键数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用FPGA Spartan 2开发板,想计算从键盘上按下的键 这是我的VHDL代码:

I`m using FPGA Spartan 2 board and want to count the keys pressed from Keyboard this is my VHDL code :

library ieee ;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

ENTITY Keyboard IS
 PORT(CLOCK : IN STD_LOGIC;
      RESET : IN STD_LOGIC;
      RK : IN STD_LOGIC_VECTOR(3 DOWNTO 1);
      DE : OUT STD_LOGIC_VECTOR(3 DOWNTO 1);
      Invalid_Key : OUT STD_LOGIC := '0';
      Seg1 : OUT STD_LOGIC_VECTOR(7 Downto 0);
      Seg2 : OUT STD_LOGIC_VECTOR(7 Downto 0);
      LEDRow1 : OUT STD_LOGIC_VECTOR(7 Downto 0);
      LEDRow2 : OUT STD_LOGIC_VECTOR(7 Downto 0);       
      Key : OUT STD_LOGIC_VECTOR(0 TO 15));
END Keyboard;

Architecture Behavier OF Keyboard IS
 Signal CLK : STD_LOGIC_VECTOR(23 DOWNTO 0);
 Signal KC : STD_LOGIC_VECTOR(1 DOWNTO 0);
 Signal KEY_PUSH : STD_LOGIC_VECTOR(4 DOWNTO 0);
 Signal KeyTemp : STD_LOGIC_VECTOR(1 TO 16) := "0000000000000000";
 Signal Counter : STD_LOGIC_VECTOR(4 downto 0) := "00000";
Begin
 DE(3) <= '0';
 DE(2 DOWNTO 1) <= KC;
 KEY_PUSH <= KC & RK;

 Process(KEY_PUSH)
 begin
  Case KEY_PUSH is
   WHEN "11101" => --0
    if Counter <= 15 then
      Invalid_Key <= '0';
      Counter <= Counter + 1;
     KeyTemp(conv_integer(Counter)) <= '0';           
    else
     Invalid_Key <= '1';
    end if;
   WHEN "00110" => --1
    if Counter <= 15 then
      Invalid_Key <= '0';
     Counter <= Counter + 1;
      KeyTemp(conv_integer(Counter)) <= '1';
    else
     Invalid_Key <= '1';
    end if;

   WHEN "00101" =>
    Invalid_Key <= '1';  -- 2
   WHEN "00011" =>
    Invalid_Key <= '1';  -- 3
   WHEN "01110" =>
    Invalid_Key <= '1';  -- 4
   WHEN "01101" =>
    Invalid_Key <= '1';  -- 5
   WHEN "01011" =>
    Invalid_Key <= '1';  -- 6
   WHEN "10110" =>
    Invalid_Key <= '1';  -- 7
   WHEN "10101" =>
    Invalid_Key <= '1';  -- 8
   WHEN "10011" =>
    Invalid_Key <= '1';  -- 9
   WHEN "11011" => -- #
    Invalid_Key <= '1';  -- #   

   WHEN "11110" => -- *
     Invalid_Key <= '0';
    KeyTemp <= "0000000000000000";
    Counter <= "00000";
   WHEN OTHERS =>   
    Invalid_Key <= '0';
  End Case;

   case Counter is
    when "00000" => -- 0
     Seg1 <= "00111111";
      Seg2 <= "00111111";
    when "00001" => -- 1
     Seg1 <= "00111111";
      Seg2 <= "00000110";
    when "00010" => -- 2
     Seg1 <= "00111111";
      Seg2 <= "01011011";
    when "00011" => -- 3
     Seg1 <= "00111111";
      Seg2 <= "01001111";
    when "00100" => -- 4
     Seg1 <= "00111111";
      Seg2 <= "01100110";
    when "00101" => -- 5
     Seg1 <= "00111111";
      Seg2 <= "01101101";
    when "00110" => -- 6
     Seg1 <= "00111111";
      Seg2 <= "01111101";
    when "00111" => -- 7
     Seg1 <= "00111111";
      Seg2 <= "00100111";
    when "01000" => -- 8
     Seg1 <= "00111111";
      Seg2 <= "01111111";
    when "01001" => -- 9
     Seg1 <= "00111111";
      Seg2 <= "01101111";
    when "01010" => -- 10
     Seg1 <= "00000110";
      Seg2 <= "00111111";
    when "01011" => -- 11
     Seg1 <= "00000110";
      Seg2 <= "00000110";
    when "01100" => -- 12
     Seg1 <= "00000110";
      Seg2 <= "01011011";
    when "01101" => -- 13
     Seg1 <= "00000110";
      Seg2 <= "01001111";
    when "01110" => -- 14
     Seg1 <= "00000110";
      Seg2 <= "01100110";
    when "01111" => -- 15
     Seg1 <= "00000110";
      Seg2 <= "01101101";
    when "10000" => -- 16
     Seg1 <= "00000110";
      Seg2 <= "01111101";
    when others =>
     Seg1 <= "00000000";
     Seg2 <= "00000000";      
   end case;

  LEDRow1 <= KeyTemp(1 to 8);
  LEDRow2 <= KeyTemp(9 to 16);  

  if Counter = 16 then
   Key <= KeyTemp;
  end if;
 End Process;

 Process(CLOCK, CLK)
 begin
  IF (Clock'EVENT AND Clock='1') THEN
   Clk <= Clk + 1;
  END IF;    
 end Process;   

 Process(Reset, CLK(10))
 begin
  IF RESET = '1' THEN
   KC <= "00";
  ELSIF (CLK(10) 'EVENT AND CLK(10)='1') THEN 
   KC <= KC + 1;    
  END IF;
 end Process;   
END Behavier;

仅接受1和0键

我想在2个7段中显示计数器值,并在LED矩阵的两行中显示0和1s,但是计数器上有问题,我认为问题是当我多次更改"Key_PUSH"或"RK"时按一个键.

I want to show counter value in 2 7segment and show the 0 and 1s in two line of LED Matrix, but there a problem on counter, I think the problem is "Key_PUSH" or "RK" are changing many times when I press a key.

如何为按下的按键创建计数器?

How I can create a counter for pressed keys ?

推荐答案

您目睹的效果称为开关的弹跳". 您需要去抖动"外部输入.

The effect you are witnessing is called "bouncing" of the switch. You need to "debounce" the external input.

外部输入与内部时钟域不同步.因此,在寄存器的建立或保持时间内的信号沿可能会引起亚稳性.您需要使用同步器将输入同步到时钟域. 两级同步器通常就足够了.

An external input is not synchronous to the internal clock domain. Thus signal edges within the setup or hold time of a register could cause metastability. You need to synchronize your input to the clock domain using a synchronizer. A two-stage synchronizer is usually sufficient.

示例代码:

library ieee;
use ieee.std_logic_1164.all;

entity synchronizer is
    generic(
        nr_of_stages : natural := 2
        );
    port(
        clk : in std_logic;
        asynchronous_input : in std_logic;
        synchronous_output : out std_logic
        );
end entity;

architecture rtl of synchronizer is
    signal registers : std_logic_vector(nr_of_stages-1 downto 0);
    -- no intialization as this could give a false edge further in the chain.
begin
    -- build the registers
    register_proc : process(clk)
    begin
        -- connect the registers end to end
        if rising_edge(clk) then
            for i in nr_of_stages-1 downto 1 loop
                registers(i) <= registers(i-1);
            end loop;
            registers(0) <= asynchronous_input;
        end if;
    end process;
    -- connect the output to the last register
    synchronous_output <= registers(nr_of_stages-1);
end architecture;


对信号进行反跳

假定输入是时钟同步的(或如上所述,是同步的).您可以通过确保信号长时间稳定来对信号进行去抖动. IE.按下按钮时启动计数器,并在计数器达到某个值时转发输入.


Debouncing the signal

Assuming the input is clock synchronous (or synchronized, as described above). You can debounce the signal by ensuring it is stable for a prolonged period. I.e. start a counter when a button is pressed and forward the input when the counter reaches a value.

示例代码:

library ieee;
use ieee.std_logic_1164.all;

entity debouncer is
    generic(
        clock_frequency : positive := 20e6; -- e.g. 20 MHz
        settle_time : time := 100 ms
        );
    port(
        clk : in std_logic;
        input : in std_logic;
        output : out std_logic
        );
end entity;

architecture rtl of debouncer is
    constant settle_time_in_clocks : positive := integer(real(clock_frequency) * settle_time / 1 sec); -- MHz to ms
    signal timer : natural range settle_time_in_clocks-1 downto 0 := settle_time_in_clocks-1;
begin
    timer_proc : process(clk)
    begin
        if rising_edge(clk) then
            if input = '0' then
                -- not asserted: reset the timer and output
                timer <= settle_time_in_clocks-1;
                output <= '0';
            elsif timer = 0 then
                -- timer finished, set the output
                output <= '1';
            else
                -- count down
                timer <= timer - 1;
            end if;
        end if;
    end process;
end architecture;


如何计算按键次数

通过检测输入从0到1的过渡来检测按键.


How to count a key press

You detect a key press by detecting a 0-to-1 transition of the input.

示例代码:

library ieee;
use ieee.std_logic_1164.all;

entity kpcnt is
    port(
        clk : in std_logic;
        rst : in std_logic;
        input_from_debouncer : in std_logic -- assumed to be synchronous to clk
        -- some output to be defined
        );
end entity;

architecture rtl of kpcnt is
    signal input_delay : std_logic;
    signal input_rising_edge : std_logic;
    use ieee.numeric_std.all;
    signal kpcounter : unsigned(7 downto 0) := (others => '0');
begin
    -- create delayed input signal
    delay_input : process(clk)
    begin
        if rising_edge(clk) then
            input_delay <= input_from_debouncer;
        end if;
    end process;
    -- detect 0->1 transition
    input_rising_edge <= '1' when input_from_debouncer = '1' and input_delay = '0' else '0';
    -- count the number of 0->1 transitions
    kpcounter_proc : process(clk)
    begin
        if rising_edge(clk) then
            if rst = '1' then
                kpcounter <= (others => '0');
            elsif input_rising_edge = '1' then
                kpcounter <= kpcounter + 1;
            end if;
        end if;
    end process;    
end architecture;


链接

以下是带有其他示例的链接:


Links

Here are some links with additional examples:

  • Debouncing.
  • This nice webpage on how to write debounce logic for an FPGA incl code. Although I would add an extra flipflop at the input for proper clock domain synchronization.

这篇关于如何计算FPGA斯巴达板上的按键数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆