1 votos

Interfaz con el teclado numérico en VHDL. Soporte para el botón Numlock

Necesito implementar una interfaz para el teclado numérico. Soy totalmente novato en Quartus y el lenguaje VHDL.
Sólo sé que el decodificador debe devolver la clave adecuada en función de la fila y la columna introducidas. Así que si por ejemplo el valor de la fila introducida es "3" y la columna es "2" entonces la salida debería ser "5" porque significa que la tecla "5" fue presionada.


El diseño funciona correctamente, pero ahora necesito implementar la tecla "numlock", que bloqueará la lectura de las teclas.
Si la tecla "numlock" está pulsada significa que el sistema debe devolver los valores correctos de las teclas pulsadas. Sin embargo, si numlock está desactivado, significa que todo el teclado no debería funcionar y debería obtener ceros o valores no inicializados en la salida.

enter image description here


multiplexor.vhd

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

entity multiplexer is
port(
    columns : in std_logic_vector(3 downto 0);
    rows : in std_logic_vector(3 downto 0);
    output_binary_key : out std_logic_vector(7 downto 0);
    is_key_pressed : out std_logic
);
end multiplexer;

architecture data_flow of multiplexer is
signal binary_key : std_logic_vector(7 downto 0);
signal tmp_numlock : std_logic;
signal flag : unsigned(3 downto 0);
begin
    process(columns, rows)
    begin
        binary_key(7 downto 4) <= rows;
        binary_key(3 downto 0) <= columns;      
        if columns = "0000" or rows = "0000" then
            is_key_pressed <= '0';
        else
            is_key_pressed <= '1';
        end if;
    end process;
    output_binary_key <= binary_key;
end data_flow;

convertidor.vhd

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity converter is
    port(
        hex_key : in std_logic_vector(7 downto 0);
        output : out std_logic_vector(7 downto 0)
    );
end converter;
architecture data_flow of converter is
    begin
    with hex_key select
    output <=       x"2F" when "00010010",  -- /
                    x"2A" when "00010011",  -- *
                    x"2D" when "00010100",  -- -
                    x"37" when "00100001",  -- 7
                    x"38" when "00100010",  -- 8
                    x"39" when "00100011",  -- 9
                    x"2B" when "00100100",  -- +
                    x"34" when "00110001",  -- 4
                    x"35" when "00110010",  -- 5
                    x"36" when "00110011",  -- 6
                    x"31" when "01000001",  -- 1
                    x"32" when "01000010",  -- 2
                    x"33" when "01000011",  -- 3
                    x"0D" when "01000100",  -- enter
                    x"30" when "01010001",  -- 0
                    x"2E" when "01010011",  -- .
                    x"00" when others;  
end data_flow;

¿Alguien puede decirme cómo debo implementar esta tecla "numlock" ahora?



EDITAR enter image description here

3voto

Ze'ev Puntos 284

No sé CUALQUIER VHDL, pero creo que podría ayudar con la idea de trabajo.

Como veo ahora, sus módulos son totalmente apátridas. No estoy seguro de si son síncronos o asíncronos, pero en este estado podrían ser fácilmente lo último.

Para implementar numlock, necesitarás algún estado interno. Una simple señal de encendido y apagado debería servir. Presionando numlock debería alternarlo, y el retorno debería basarse en él. Lo último es más fácil, lo primero es un poco más diferente.

Yo sugeriría crear una nueva señal - numlock_pressed . Debería basarse simplemente en hex_key . Es posible que tenga que rebotar esta señal. Entonces se necesita una simple conmutación sincrónica del estado interno.

3voto

Saad Bin Shahid Puntos 6

Basado en Sasszem Aquí tenemos una implementación en VHDL con sincronizadores, desbordadores y un estado interno dentro de Multiplexer para recordar el estado de NUM LOCK que Converter utiliza para seleccionar la conversión correcta. La simulación muestra la salida ASCII tanto en formato sin signo como en carácter.

Sincronizador

Sincroniza la entrada (señales de fila y columna) con el reloj del sistema.

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

entity Sync is
    generic
    (
        SYNC_BITS: positive := 3;  -- Number of bits in the synchronisation buffer (2 minimum).
        BIT_WIDTH: positive := 8
    );
    port
    (
        clock : in std_logic;
        input : in std_logic_vector(BIT_WIDTH - 1 downto 0);  -- Asynchronous input.
        output: out std_logic_vector(BIT_WIDTH - 1 downto 0)  -- Synchronous output.
    );
end entity;

architecture V1 of Sync is

    constant SYNC_BUFFER_MSB: positive := SYNC_BITS - 1;
    subtype TSyncBuffer is std_logic_vector(SYNC_BUFFER_MSB downto 0);
    type TSyncBuffers is array(0 to BIT_WIDTH - 1) of TSyncBuffer;
    signal sync_buffers: TSyncBuffers;

begin

    assert SYNC_BITS >= 2 report "Need a minimum of 2 bits in the synchronisation buffer.";

    process(all)
    begin
        if rising_edge(clock) then
            for i in 0 to BIT_WIDTH - 1 loop
                sync_buffers(i) <= sync_buffers(i)(SYNC_BUFFER_MSB - 1 downto 0) & input(i);
            end loop;
        end if;
        for i in 0 to BIT_WIDTH - 1 loop
            output(i) <= sync_buffers(i)(SYNC_BUFFER_MSB);
        end loop;
    end process;

end architecture;

Destapador

Desembolsa la entrada sincronizada (señales de fila y columna), y a continuación emite un change estroboscópico cuando se ha desbordado con éxito. Esta luz estroboscópica se utiliza para activar Multiplexer para procesar la pulsación de la tecla.

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

entity Debounce is
    generic
    (
        CLOCK_PERIOD   : time := 20 ns;
        DEBOUNCE_PERIOD: time := 20 ms;  -- Rule of thumb for a keyboard button.
        BIT_WIDTH      : positive := 8
    );
    port
    (
        clock : in std_logic;
        input : in std_logic_vector(BIT_WIDTH - 1 downto 0);                        -- Asynchronous and noisy input.
        output: out std_logic_vector(BIT_WIDTH - 1 downto 0) := (others => '0');    -- Synchronised, debounced and filtered output.
        change: out std_logic := '0'                                                -- Goes high for 1 clock cycle on change of input.
    );
end entity;

architecture V1 of Debounce is

    constant MAX_COUNT: natural := DEBOUNCE_PERIOD / CLOCK_PERIOD - 1;
    signal counter: natural range 0 to MAX_COUNT := 0;  -- Specify the range to reduce number of bits that are synthesised.

begin

    process(all)
        variable change_internal: std_logic := '0';
    begin
        if rising_edge(clock) then
            counter <= 0;   -- Freeze the counter by default to reduce switching losses when input equals output.
            change <= '0';  -- Goes high for 1 clock cycle on change of input.

            if counter = MAX_COUNT then     -- If successfully debounced, notify what happened.
                output <= input;
                change <= change_internal;  -- Goes high for 1 clock cycle on change of input.
            elsif input /= output then      -- Hysteresis.
                counter <= counter + 1;         -- Only increment when input and output differ.
            end if;
        end if;

        -- Change detection.
        if input /= output then
            change_internal := '1';
        else
            change_internal := '0';
        end if;
    end process;

end architecture;

Multiplexor

Se ha añadido un estroboscopio de tecla pulsada para activar el procesamiento de la tecla. Cambia el estado de BLOQUEO DE NÚMERO si la tecla presionada es la tecla de BLOQUEO DE NÚMERO. Este estado es utilizado por Converter para convertir la clave en ASCII.

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

entity Multiplexer is
    port
    (
        reset: in std_logic;
        clock: in std_logic;
        key_pressed_strobe: in std_logic;
        columns : in std_logic_vector(3 downto 0);
        rows : in std_logic_vector(3 downto 0);
        binary_key : out std_logic_vector(7 downto 0);
        is_key_pressed : out std_logic;
        is_num_lock_on : out std_logic
    );
end Multiplexer;

architecture data_flow of Multiplexer is
    signal is_key_pressed_internal : std_logic;

begin
    process(all)
    begin
        if reset then
            binary_key <= "00000000";
            is_key_pressed <= '0';
            is_num_lock_on <= '0';
        elsif rising_edge(clock) then
            if key_pressed_strobe then
                binary_key <= rows & columns;
                is_key_pressed <= is_key_pressed_internal;
                if columns = "0001" and rows = "0001" then
                    is_num_lock_on <= not is_num_lock_on;
                end if;
            end if;
        end if;

        if columns = "0000" or rows = "0000" then
            is_key_pressed_internal <= '0';
        else
            is_key_pressed_internal <= '1';
        end if;
    end process;
end data_flow;

Convertidor

Se ha añadido una señal is_num_lock_on para indicar el estado de bloqueo de números. Se han añadido un par de subtipos llamados TKey y TAscii con algunas constantes para cada clave para hacer el código más legible y mantenible.

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

entity Converter is
    port
    (
        hex_key : in std_logic_vector(7 downto 0);
        is_num_lock_on : in std_logic;
        output : out std_logic_vector(7 downto 0)
    );
end Converter;

architecture data_flow of Converter is
    subtype TKey is std_logic_vector(7 downto 0);
    subtype TAscii is std_logic_vector(7 downto 0);

    constant KEY_NUMLOCK  : TKey := "00010001";  -- Num Lock
    constant KEY_0        : TKey := "01010001";  -- 0
    constant KEY_1        : TKey := "01000001";  -- 1
    constant KEY_2        : TKey := "01000010";  -- 2
    constant KEY_3        : TKey := "01000011";  -- 3
    constant KEY_4        : TKey := "00110001";  -- 4
    constant KEY_5        : TKey := "00110010";  -- 5
    constant KEY_6        : TKey := "00110011";  -- 6
    constant KEY_7        : TKey := "00100001";  -- 7
    constant KEY_8        : TKey := "00100010";  -- 8
    constant KEY_9        : TKey := "00100011";  -- 9
    constant KEY_MULTIPLY : TKey := "00010011";  -- *
    constant KEY_DIVIDE   : TKey := "00010010";  -- /
    constant KEY_PLUS     : TKey := "00100100";  -- +
    constant KEY_SUBTRACT : TKey := "00010100";  -- -
    constant KEY_DOT      : TKey := "01010011";  -- .
    constant KEY_ENTER    : TKey := "01000100";  -- Enter

    constant ASCII_0        : TAscii := x"30"; -- 0
    constant ASCII_1        : TAscii := x"31"; -- 1
    constant ASCII_2        : TAscii := x"32"; -- 2
    constant ASCII_3        : TAscii := x"33"; -- 3
    constant ASCII_4        : TAscii := x"34"; -- 4
    constant ASCII_5        : TAscii := x"35"; -- 5
    constant ASCII_6        : TAscii := x"36"; -- 6
    constant ASCII_7        : TAscii := x"37"; -- 7
    constant ASCII_8        : TAscii := x"38"; -- 8
    constant ASCII_9        : TAscii := x"39"; -- 9
    constant ASCII_MULTIPLY : TAscii := x"2A"; -- *
    constant ASCII_DIVIDE   : TAscii := x"2F"; -- /
    constant ASCII_PLUS     : TAscii := x"2B"; -- +
    constant ASCII_SUBTRACT : TAscii := x"2D"; -- -
    constant ASCII_DOT      : TAscii := x"2E"; -- .
    constant ASCII_ENTER    : TAscii := x"0D"; -- Enter
    constant ASCII_NULL     : TAscii := x"00"; -- Null

begin
    process(all)
    begin
        if is_num_lock_on then
            case hex_key is
                when KEY_0        => output <= ASCII_0;
                when KEY_1        => output <= ASCII_1;
                when KEY_2        => output <= ASCII_2;
                when KEY_3        => output <= ASCII_3;
                when KEY_4        => output <= ASCII_4;
                when KEY_5        => output <= ASCII_5;
                when KEY_6        => output <= ASCII_6;
                when KEY_7        => output <= ASCII_7;
                when KEY_8        => output <= ASCII_8;
                when KEY_9        => output <= ASCII_9;
                when KEY_MULTIPLY => output <= ASCII_MULTIPLY;
                when KEY_DIVIDE   => output <= ASCII_DIVIDE;
                when KEY_PLUS     => output <= ASCII_PLUS;
                when KEY_SUBTRACT => output <= ASCII_SUBTRACT;
                when KEY_DOT      => output <= ASCII_DOT;
                when KEY_ENTER    => output <= ASCII_ENTER;
                when others       => output <= ASCII_NULL;
            end case;
        else
            case hex_key is
                when KEY_MULTIPLY => output <= ASCII_MULTIPLY;
                when KEY_DIVIDE   => output <= ASCII_DIVIDE;
                when KEY_PLUS     => output <= ASCII_PLUS;
                when KEY_SUBTRACT => output <= ASCII_SUBTRACT;
                when KEY_DOT      => output <= ASCII_DOT;
                when KEY_ENTER    => output <= ASCII_ENTER;
                when others       => output <= ASCII_NULL;
            end case;
        end if;
    end process;
end data_flow;

Banco de pruebas

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;

entity Keypad_TB is
end;

architecture V1 of Keypad_TB is

    constant CLOCK_PERIOD   : time := 50 ns;
    constant DEBOUNCE_PERIOD: time := 200 ns;  -- Use ~20 ms for actual keypad.

    signal halt_sys_clock: boolean := false;

    signal reset: std_logic := '0';
    signal clock: std_logic := '0';
    signal input: std_logic_vector(7 downto 0);
    signal input_sync: std_logic_vector(7 downto 0);
    signal input_sync_db: std_logic_vector(7 downto 0);
    alias rows is input_sync_db(7 downto 4);
    alias columns is input_sync_db(3 downto 0);
    signal change: std_logic;
    signal key: std_logic_vector(7 downto 0);
    signal ascii: std_logic_vector(7 downto 0);
    signal is_key_pressed: std_logic;
    signal is_num_lock_on: std_logic;

    component Sync is
        generic
        (
            SYNC_BITS: positive := 3;  -- Number of bits in the synchronisation buffer (2 minimum).
            BIT_WIDTH: positive := 8
        );
        port
        (
            clock : in std_logic;
            input : in std_logic_vector(BIT_WIDTH - 1 downto 0);  -- Asynchronous input.
            output: out std_logic_vector(BIT_WIDTH - 1 downto 0)  -- Synchronous output.
        );
    end component;

    component Debounce is
        generic
        (
            CLOCK_PERIOD   : time := 20 ns;
            DEBOUNCE_PERIOD: time := 20 ms;  -- Rule of thumb for a keyboard button.
            BIT_WIDTH      : positive := 8
        );
        port
        (
            clock : in std_logic;
            input : in std_logic_vector(BIT_WIDTH - 1 downto 0);                        -- Asynchronous and noisy input.
            output: out std_logic_vector(BIT_WIDTH - 1 downto 0) := (others => '0');    -- Synchronised, debounced and filtered output.
            change: out std_logic := '0'                                                -- Goes high for 1 clock cycle on change of input.
        );
    end component;

    component Multiplexer is
        port
        (
            reset: in std_logic;
            clock: in std_logic;
            key_pressed_strobe: in std_logic;
            columns : in std_logic_vector(3 downto 0);
            rows : in std_logic_vector(3 downto 0);
            binary_key : out std_logic_vector(7 downto 0);
            is_key_pressed : out std_logic;
            is_num_lock_on : out std_logic
        );
    end component;

    component Converter is
        port
        (
            hex_key : in std_logic_vector(7 downto 0);
            is_num_lock_on : in std_logic;
            output : out std_logic_vector(7 downto 0)
        );
    end component;

begin

    ClockGenerator:
    process
    begin
        while not halt_sys_clock loop
            clock <= not clock;
            wait for CLOCK_PERIOD / 2.0;
        end loop;
        wait;
    end process ClockGenerator;

    Stimulus:
    process
        constant NUM_NOISE_SAMPLES: positive := 10;
        constant SWITCH_TIME: time := 2 * DEBOUNCE_PERIOD;
        variable seed1: positive := 1;
        variable seed2: positive := 1;
        variable rrand: real;
        variable nrand: natural;

        -- Performs noisy transition of sig from current value to final value.
        procedure NoisyTransition(signal sig: out std_logic_vector(7 downto 0); final: std_logic_vector(7 downto 0)) is
            constant initial: std_logic_vector(7 downto 0) := sig;
        begin
            for n in 1 to NUM_NOISE_SAMPLES loop
                uniform(seed1, seed2, rrand);
                nrand := natural(round(rrand));
                if nrand = 0 then
                    sig <= initial;
                else
                    sig <= final;
                end if;
                wait for CLOCK_PERIOD / 5.0;
            end loop;
            sig <= final;
            wait for SWITCH_TIME;
        end;

    begin
        reset <= '0';
        input <= "00000000";
        wait for 3 ns;
        reset <= '1';
        wait for CLOCK_PERIOD;
        reset <= '0';

        --
        -- Input
        --

        -- Perform some noisy presses and releases.
        NoisyTransition(input, "00010001");  -- Row 1, Column 1: Num Lock
        NoisyTransition(input, "00000000");

        NoisyTransition(input, "00100010");  -- Row 2, Column 2: 8
        NoisyTransition(input, "00000000");

        NoisyTransition(input, "00110011");  -- Row 3, Column 3: 6
        NoisyTransition(input, "00000000");

        NoisyTransition(input, "01000100");  -- Row 4, Column 4: ENTER
        NoisyTransition(input, "00000000");

        NoisyTransition(input, "00010001");  -- Row 1, Column 1: Num Lock
        NoisyTransition(input, "00000000");

        NoisyTransition(input, "00100010");  -- Row 2, Column 2: 8
        NoisyTransition(input, "00000000");

        NoisyTransition(input, "00110011");  -- Row 3, Column 3: 6
        NoisyTransition(input, "00000000");

        NoisyTransition(input, "01000100");  -- Row 4, Column 4: ENTER
        NoisyTransition(input, "00000000");

        halt_sys_clock <= true;
        wait;
    end process;

    S1:
        Sync
        generic map
        (
            SYNC_BITS => 3,
            BIT_WIDTH => 8   -- 4 bits for rows and 4 bits for columns.
        )
        port map
        (
            clock => clock,
            input => input,
            output => input_sync
        );

    D1:
        Debounce
        generic map
        (
            CLOCK_PERIOD    => CLOCK_PERIOD,
            DEBOUNCE_PERIOD => DEBOUNCE_PERIOD,
            BIT_WIDTH       => 8  -- 4 bits for rows and 4 bits for columns.
        )
        port map
        (
            clock  => clock,
            input  => input_sync,
            output => input_sync_db,
            change => change
        );

    M1:
        Multiplexer
        port map
        (
            reset               => reset,
            clock               => clock,
            key_pressed_strobe  => change,
            columns             => columns,
            rows                => rows,
            binary_key          => key,
            is_key_pressed      => is_key_pressed,
            is_num_lock_on      => is_num_lock_on
        );

    C1:
        Converter
        port map
        (
            hex_key         => key,
            is_num_lock_on  => is_num_lock_on,
            output          => ascii
        );

end architecture;

Simulación de teclado

Simulation of Keypad Quartus BDF del teclado

Quartus BDF of Keypad Quartus RTL del teclado

Quartus RTL of Keypad

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X