【问题标题】:VHDL one if holds true in every case and the other doesn'tVHDL 一个 if 在每种情况下都成立,而另一个则不成立
【发布时间】:2014-12-23 01:24:14
【问题描述】:

接下来的 ssd 过程是为了向我展示我为这两个用户所拥有的东西。代码 atm 似乎可以很好地为两个用户存储数据,并且可以在任何给定时间调用它。然而问题是我似乎无法改变这样一个事实,即每当我按下任一按钮时 - 以小数点 1 增加或减少任一用户的数字保持。无论如何,它都会更改第一个用户的号码。 switch(7) 是“1”还是“0”都没有关系。此外,我可以选择第二个用户,尽管我也无法对他进行任何更改-按钮仅影响第一个用户-。这是我的问题,我不知道为什么会发生这种情况,但我唯一的直觉是我这里有一个糟糕的设计。无论如何,下面是感兴趣和乐于助人的代码:

process (clk)

begin

    if(switch(7) <= '1') then --first user

        if(rising_edge(clk)) then
            if(btn(0)='1' and lastButtonState(0) = '0') then--increase by 1
                user0 <= user0 + "001";
            end if;
            lastButtonState(0) <= btn(0);
            if(btn(1) = '1' and lastButtonState(1) = '0') then --decrease by 1
                user0 <= user0 + "111";
            end if;
            lastButtonState(1) <= btn(1);
        end if;



    elsif (switch(6) = '1') then --second user
        if(rising_edge(clk)) then
            if(btn(0) = '1' and lastButtonState(0) = '0') then
                user1 <= user1 + "001";
            end if;
        lastButtonState(0) <= btn(0);

            if(btn(1) = '1' and lastButtonState(1) = '0') then

                user1 <= user1 + "111";

            end if;
            lastButtonState(1) <= btn(1);
        end if;


    end if;


end process;
process (user0, user1, switch)
begin

    if(switch(7) = '1') then
        case user0 is
            when "000" => a_to_g <= "0000001";
            when "001" => a_to_g <= "1001111";
            when "010" => a_to_g <= "0010010";
            when "011" => a_to_g <= "0000110";
            when "100" => a_to_g <= "1001100";
            when "101" => a_to_g <= "0100100";
            when "110" => a_to_g <= "0100000";
            when others => a_to_g <= "0001111";
        end case;


    elsif (switch(6) = '1') then
       case user1 is
           when "000" => a_to_g <= "0000001";
           when "001" => a_to_g <= "1001111";
           when "010" => a_to_g <= "0010010";
           when "011" => a_to_g <= "0000110";
           when "100" => a_to_g <= "1001100";
           when "101" => a_to_g <= "0100100";
           when "110" => a_to_g <= "0100000";
           when others => a_to_g <= "0001111";
       end case;

    end if;
end process;

【问题讨论】:

  • 该代码有几个问题。但是,目前引起麻烦的具体问题可能是您实际上并未测试 Switch 7 = '1'。小于或等于,是的。等于,没有。
  • 什么是ssd进程?固态驱动器还是七段显示器?请不要使用不常见的缩写。
  • 您还可以标记 VHDL 中的任何语句,包括过程语句。这两个进程中的哪一个被认为是 ssd?什么是“密码ATM”?您的两个进程不包含Minimal, Complete, and Verifiable example

标签: button if-statement vhdl store


【解决方案1】:

这段代码的一些提示:

  • 您的代码描述了门控时钟 - 这不是好的编码风格!
    把所有东西都放在if rising_edge() then 里面(例外:异步重置)
  • 您可以删除一个 7 段。解码器块,如果您将第二个进程分为多路复用器和解码器:

    process (user0, user1, switch)
      variable temp : std_logic_vector(2 downto 0);
    begin
      if(switch(7) = '1') then
        temp  := user0;
      elsif (switch(6) = '1') then
        temp  := user1;
      else
        temp  := "000";
      end if;
    
      case temp is
        when "000" => a_to_g <= "0000001";
        when "001" => a_to_g <= "1001111";
        when "010" => a_to_g <= "0010010";
        when "011" => a_to_g <= "0000110";
        when "100" => a_to_g <= "1001100";
        when "101" => a_to_g <= "0100100";
        when "110" => a_to_g <= "0100000";
        when others => a_to_g <= "0001111";
      end case;
    end process;
    
  • 我建议从主进程中提取按钮信号的上升沿检测。边缘检测是一个信号预处理步骤,应该与控制逻辑分离。如果您正在进行边缘检测:您是否对信号进行了同步和去抖动?

    -- edge detection in 2 lines
    btn_d  <= btn when rising_edge(clk);  -- delay (*_d) all button signals for one cycle
    btn_re <= not btn_d and btn;          -- calculate rising edge (*_re) strobe signal for every button
    
  • 为什么不用减号来减 1 而不是加 -1 呢?

关于评论 1 的编辑 1:

我假设您使用的是配备(按钮)和(滑动/dip)开关的标准阐述板。

首先,每个外部异步信号都必须与设计的内部时钟同步,以防止元稳定性问题。这通常通过实现双触发器同步器(2 个 D-FF 作为链,没有移位寄存器)来完成。

-- example for a Xilinx ML505 board
port map (
  -- ...
  ML505_GPIO_Button_CPU_Reset_n  : in  STD_LOGIC;
  ML505_GPIO_Button_West         : in  STD_LOGIC;
  ML505_GPIO_Button_East         : in  STD_LOGIC;
  ML505_GPIO_Switches            : in  STD_LOGIC_VECTOR(7 downto 0);
);

-- signals
architecture ...
  -- signals to convert low-active signals to high-active
  signal ML505_GPIO_Button_Reset : STD_LOGIC;

  -- signals for double synchronization
  signal GPIO_Buttons_async    : STD_LOGIC_VECTOR(2 downto 0);
  signal GPIO_Buttons_meta     : STD_LOGIC_VECTOR(2 downto 0)  := (others => '0');
  signal GPIO_Buttons_sync     : STD_LOGIC_VECTOR(2 downto 0)  := (others => '0');
  signal GPIO_Buttons          : STD_LOGIC_VECTOR(2 downto 0);
  signal GPIO_Buttons_d        : STD_LOGIC_VECTOR(2 downto 0)  := (others => '0');
  signal GPIO_Buttons_re       : STD_LOGIC_VECTOR(2 downto 0);

  signal GPIO_Switches_async   : STD_LOGIC_VECTOR(7 downto 0);
  signal GPIO_Switches_meta    : STD_LOGIC_VECTOR(7 downto 0)  := (others => '0');
  signal GPIO_Switches_sync    : STD_LOGIC_VECTOR(7 downto 0)  := (others => '0');

-- ...
begin
  -- source code to pre process external signals
  -- =============================================
  -- convert low-active signals to high-active
  ML505_GPIO_Button_Reset <= ML505_GPIO_Button_Reset_n;

  -- input synchronization
  GPIO_Buttons_async(0)  <= ML505_GPIO_Button_Reset;
  GPIO_Buttons_async(1)  <= ML505_GPIO_Button_West;
  GPIO_Buttons_async(2)  <= ML505_GPIO_Button_East;
  GPIO_Switches_async    <= ML505_GPIO_Switches;

  -- double FF synchronizer
  GPIO_Buttons_meta  <= GPIO_Buttons_async  when rising_edge(Clock);
  GPIO_Switches_meta <= GPIO_Switches_async when rising_edge(Clock);

  GPIO_Buttons_sync  <= GPIO_Buttons_meta  when rising_edge(Clock);
  GPIO_Switches_sync <= GPIO_Switches_meta when rising_edge(Clock);

下一步是去抖动信号,因为许多电路板不使用无抖动元件(这可以通过简单的电容器或外部去抖动电路以机械方式完成)。所以如果你不确定或者你的板子没有去抖动的用户输入,你必须自己实现某个电路。 Debounceing meens,你的信号至少在去抖持续时间内是稳定的。这个时间可以是 5 毫秒。

deb1 : entity PoC.io_Debounce
  generic map (
    ports  => 3
  )
  port map (
    Clock  => Clock,
    Input  => GPIO_Buttons_sync,
    Output => GPIO_Buttons
  );

去抖电路只是抑制毛刺的滤波器。结果是一个“标志”信号(长时间的高或低)。

在大多数情况下,用户输入会馈送到 FSM 或其他任何东西中。这些电路需要选通信号(高有效逻辑:一个周期的高脉冲)。这种“转换”可以通过边缘检测(上升或下降)来完成。

-- edge detection
GPIO_Buttons_d  <= GPIO_Buttons when rising_edge(Clock);
GPIO_Buttons_re <= not GPIO_Buttons_d and GPIO_Buttons;

-- final renaming after pre processing
GPIO_Button_Reset <= GPIO_Buttons_re(0);
GPIO_Button_West  <= GPIO_Buttons_re(2);
GPIO_Button_East  <= GPIO_Buttons_re(1);

现在您可以在电路中使用经过预处理的信号。

附录:

a_d &lt;= a when rising_edge(Clock); 行是没有启用和复位的简单 D-FF 的缩写形式。或者,您可以使用标准流程。 a_re &lt;= not a_d and a; 行检查 a 是否为零,现在为一 -> 上升沿条件。有关单线人字拖的更多详细信息,请参阅我的其他帖子。 LINK

【讨论】:

  • 关于 7 段的想法。太棒了!我没有考虑到这一点。我一定会实施的。我有一个问题。您能否详细说明“从我的主进程中提取按钮信号的上升沿检测”,因为我不理解您编写的按钮代码和去抖动,因为按钮按原样工作?
  • @Briandrummond 我不明白你的意思。这个子句 -if(switch(7) = '1') then- 检查 switch(7) 是打开还是关闭?如果它是 1 那么它继续执行下面的代码。我弄错了吗?为了澄清我的问题,无论 switch(7) 的输入如何,switch(7) 都会执行下面的代码,令人惊讶的是,我对第二个用户 -switch(6) 的编码完全相同,但它不起作用。
  • @royalgobbal :“这个子句不是 -if(switch(7) = '1') then - 检查 switch(7) 是打开还是关闭吗?”是的。但是您问题中的代码不同。
  • 赞成,因为这是一个很好的答案,但更重要的是,我从来没有想过你可以通过btn_d &lt;= btn when rising_edge(clk); 来推断单行中的失败。
  • @QuantumRipple 原来是一个同学的解决方案。没有人相信他!但它有效!我只是通过使用 functins 将他的想法扩展到其他 FF 类型。也可以编写一个计数器函数。看看这个文件,这是我完整的组件包:code.google.com/p/picoblaze-library/source/browse/vhdl/lib_PoC/…
猜你喜欢
  • 1970-01-01
  • 2022-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-15
  • 2013-09-03
  • 1970-01-01
  • 2020-02-03
相关资源
最近更新 更多