用于键盘接口的 vhdl 代码

Posted

技术标签:

【中文标题】用于键盘接口的 vhdl 代码【英文标题】:vhdl code for keypad interfacing 【发布时间】:2015-11-08 17:58:17 【问题描述】:
 entity hex_kp is
    Port ( row : out  STD_LOGIC_VECTOR (3 downto 0);
           coloumn : in  STD_LOGIC_VECTOR (3 downto 0);
           sevenseg : out  STD_LOGIC_VECTOR (7 downto 0);
           ca : out  STD_LOGIC_VECTOR (3 downto 0));
end hex_kp;

architecture Behavioral of hex_kp is

begin

 ca <="0111";

 if(row = "0111") then

     if(coloumn = "0111") then sevenseg <= "00000110" ;
    elsif (coloumn = "1011") then sevenseg <= "01011011" ;
     elsif (coloumn = "1101") then sevenseg <= "01001111" ;
     elsif (coloumn = "1110") then sevenseg <= "01110001" ;
     end if;
end if;

这是我用于 Basys2 的 4x4 键盘扫描仪的 vhdl 代码的一部分。它给 "if(row = "0111") then" 语句一个错误。我找不到请帮忙的原因。

【问题讨论】:

读取“OUT”端口无效,除非您指定 VHDL-2008。 并且您不(应该)被允许根据 -2008 中的输出值对其他信号的值做出决定。这是一项旨在支持验证构造的功能。 信号row的值在哪里赋值? 您是否将 Digilent 键盘用作 Pmod 设备?有浮动输入的可能性……您应该在 FPGA 的 IOB 中启用上拉。 我找到了 4×4 键盘的原始 Digilent 示例代码。您必须开车 column 并阅读 row!这可以防止您使用浮动输入。 【参考方案1】:

可以使用条件信号赋值语句:

architecture behave of hex_kp is

begin

     ca <="0111";

--  if(row = "0111") then
--
--      if(coloumn = "0111") then sevenseg <= "00000110" ;
--     elsif (coloumn = "1011") then sevenseg <= "01011011" ;
--      elsif (coloumn = "1101") then sevenseg <= "01001111" ;
--      elsif (coloumn = "1110") then sevenseg <= "01110001" ;
--      end if;
-- end if;

    sevenseg <= "00000110" when coloumn = "0111" and row = "0111" else
                "01011011" when coloumn = "1011" and row = "0111" else
                "01001111" when coloumn = "1101" and row = "0111" else
                "01110001" when coloumn = "1110" and row = "0111" else
                "00000000" when                      row = "0111";
end architecture behave;

请注意,与您的 Stack Exchange 问题 (vhdl code interfacing keypad with fpga) 一样,sevenseg 上存在推断的闩锁,这是由于使用 row = "0111" 作为分配条件而引起的。

上述架构给出的结果与我对您的 Stack Exchange 问题 (vhdl code interfacing keypad with fpga) 的回答相同。

您修改后的代码分析、阐述和添加的测试平台模拟了上述架构:

摆脱闩锁就像从上面的条件信号分配中的最终选择中删除 row = "0111" 一样简单,或者在 Stack Exchange 示例中使用 case 语句,为封闭的 if 语句提供 else 。

以使用行作为输入为前提的整个代码,包括测试台和两种架构:

library ieee;
use ieee.std_logic_1164.all;

entity hex_kp is
    port ( 
        row:        in  std_logic_vector (3 downto 0);
        coloumn:    in  std_logic_vector (3 downto 0);  -- 'column 'is mispelled
        sevenseg:   out std_logic_vector (7 downto 0);  -- why is 7 segs 8 long?
        ca :        out std_logic_vector (3 downto 0)
    );
end entity hex_kp;

architecture behavioral of hex_kp is
    -- signal row: std_logic_vector(3 downto 0);  -- who drive row?
begin  -- this was missing
UNLABELLED:
    process(row, coloumn)  -- was 'column' (didn't match declaration)
    begin
        ca <="0111";
        if row = "0111" then
            case coloumn is
                when "0111" =>
                    sevenseg <= "00000110"; 
                when "1011" => 
                    sevenseg <= "01011011";  
                when "1101" =>
                    sevenseg <= "01001111";
                when "1110" =>
                 sevenseg <= "01110001";
                when others =>
                    sevenseg <= (others => '0');
            end case;
        end if;
    end process;
end architecture behavioral;

architecture behave of hex_kp is

begin

     ca <="0111";

--  if(row = "0111") then
--
--      if(coloumn = "0111") then sevenseg <= "00000110" ;
--     elsif (coloumn = "1011") then sevenseg <= "01011011" ;
--      elsif (coloumn = "1101") then sevenseg <= "01001111" ;
--      elsif (coloumn = "1110") then sevenseg <= "01110001" ;
--      end if;
-- end if;

    sevenseg <= "00000110" when coloumn = "0111" and row = "0111" else
                "01011011" when coloumn = "1011" and row = "0111" else
                "01001111" when coloumn = "1101" and row = "0111" else
                "01110001" when coloumn = "1110" and row = "0111" else
                "00000000" when                      row = "0111";
end architecture behave;

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

entity hex_kp_tb is
end entity;

architecture foo of hex_kp_tb is
    signal row:         std_logic_vector (3 downto 0);
    signal coloumn:     std_logic_vector (3 downto 0);
    signal sevenseg:    std_logic_vector (7 downto 0);
    signal ca:          std_logic_vector (3 downto 0);
    signal count:       unsigned (7 downto 0) := (others => '0');
begin

DUT: 
    entity work.hex_kp
        port map (
            row => row,
            coloumn => coloumn,
            sevenseg => sevenseg,
            ca => ca
        );
STIMULUS:
    process
    begin
        row <= std_logic_vector (count(3 downto 0));
        coloumn <= std_logic_vector (count(7 downto 4));
        wait for 100 ns;
        count <= count + 1;
        if count = "11111111" then
            wait;
        end if;
    end process;
end architecture;

【讨论】:

我假设sevenseg : out std_logic_vector (7 downto 0) 中的第 8 段/第 7 位是点:)。 那么,Paebbels 显示的字符是什么? 您的代码有注释:-- why is 7 segs 8 long? 我指的是。通常 7 段显示器有 7 个阴极引脚,命名为 a..g(每个 LED 段一个)和一个用于点的第 8 个引脚。这可以解释为什么 OP 将端口声明为 7 downto 0 那么显示的字符是什么? Baysys2 UCF 显示 7 段输出、dp 和 4 个阴极。第一个是'1',第二个是'2',第三个是向后的'E',第四个是'E',假设一个是打开的,最左边是你的小数点,它是像共阴极一样的段和 g 是下一个最左边的。关键是它没有记录在案。【参考方案2】:

您正在尝试在并发上下文中使用if 语句。但是,if 语句需要在顺序上下文中 - 例如 process 语句:

process(row, column)
begin
    if(row = "0111") then
         if(coloumn = "0111") then
             sevenseg <= "00000110";
         elsif(coloumn = "1011") then 
             sevenseg <= "01011011";
         elsif(coloumn = "1101") then
             sevenseg <= "01001111";
         elsif(coloumn = "1110") then
             sevenseg <= "01110001";
         end if;
    end if;
end process;

但是 - 请注意,如果您综合上述内容,它很可能最终会为您提供一组不错的锁存器(您通常不想要),因为您没有在所有可能的情况下分配 sevenseg(如果row0111 不同,或者如果 coloumn 不匹配任何 if 语句)。

要修复它,要么 1) 使用时钟 process,要么 2) 如果 rowcoloumn 与指定情况之一不匹配,则将 sevenseg 分配给默认值。例如:

process(row, column)
begin
    sevenseg <= (others => '0');
    if(row = "0111") then
         if(coloumn = "0111") then
             sevenseg <= "00000110";
         elsif(coloumn = "1011") then 
             sevenseg <= "01011011";
         elsif(coloumn = "1101") then
             sevenseg <= "01001111";
         elsif(coloumn = "1110") then
             sevenseg <= "01110001";
         end if;
    end if;
end process;

我添加了sevenseg &lt;= (others =&gt; '0');,这将使sevenseg默认为所有0,如果没有命中指定的情况-如果是,它们将覆盖添加的行,并设置@987654339 @ 到适当的值。

一个更好的方法是使用case 语句,因为这可能更好地描述了你真正想要的:

process(row, column)
begin
    if(row = "0111") then
         case coloumn is
         when "0111" =>
             sevenseg <= "00000110";
         when "1011" =>
             sevenseg <= "01011011";
         when "1101" =>
             sevenseg <= "01001111";
         when "1110" =>
             sevenseg <= "01110001";
         when others =>
             sevenseg <= (others => '0');
         end case;
    else
        sevenseg <= (others => '0');
    end if;
end process;

【讨论】:

我添加了进程,但是现在它给该行提供了错误。 if 语句是一个顺序语句,它不仅可以在进程中找到(例如子程序)。恰好 Ayca Ekin 试图在适合并发语句的地方使用 if 语句,这需要条件信号赋值语句包含 if 语句或 case 语句的进程。 该错误与布赖恩对您的问题的评论有关。按照 Brian 在 Stack Exchange (vhdl code interfacing keypad with fpga) 上的建议显示错误消息。 啊-感谢您的详细说明,稍微调整了答案。

以上是关于用于键盘接口的 vhdl 代码的主要内容,如果未能解决你的问题,请参考以下文章

VHDL串口通信 在FPGA开发板上测试 并解决没有识别到下载接口USB_Blaster(No Hardware问题)

单片机的键盘接口连接分为哪几类?说明各自的工作原理。键盘消抖是啥有哪几种方法

带有 VHDL 代码的 FPGA 上的声音发生器

VHDL语法相关

VHDL语法相关

VHDL语法相关