【问题标题】:Having troubles with running FSM on Nexys2在 Nexys2 上运行 FSM 时遇到问题
【发布时间】:2014-06-22 06:29:55
【问题描述】:

我正在尝试运行一个扫描 LED 的简单 FSM。我通过将位向左移动来应用此逻辑,为此使用 & 运算符。它根本不移动,只有 LSB 发光,就是这样,我也减慢了时钟,使用 1.5Hz 时钟。有人请告诉我这里出了什么问题。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity scan is
Port ( 
            clk         : in    STD_LOGIC;
            led         : out   STD_LOGIC_VECTOR (7 downto 0);
            reset       : in    STD_LOGIC
        );
end scan;
architecture Behavioral of scan is

Type state is
    (
    RESET_ST,
    S1
    );

    signal n_state : state;
    signal c_state : state;

    signal input_temp   :unsigned (7 downto 0):= "00000001";

begin
--------------------------------------------------------------------------
--------------------------CURRENT STATE ASSIGNMENT------------------------
--------------------------------------------------------------------------

STATE_ASSIGNMENT: process (clk, reset)
    begin
    if (reset = '1') then
            c_state <= RESET_ST;
    elsif  (clk'event and clk = '1') then
            c_state <= n_state;
    end if;
    end process STATE_ASSIGNMENT;


--------------------------------------------------------------------------
----------------------------- INTPUT BLOCK--------------------------------  
--------------------------------------------------------------------------

INPUT_BLOCK : process (c_state) 
    begin
case (c_state) is

when RESET_ST   =>  
input_temp  <= "00000001";
n_state         <= S1;

when S1             =>
    input_temp  <= input_temp (6 downto 0) & '0';
    n_state         <= S1;
when others => 
n_state         <= RESET_ST;

end case;
end process;
--------------------------------------------------------------------------
----------------------------- OUTPUT BLOCK--------------------------------  
--------------------------------------------------------------------------

OUTPUT_BLOCK : process (c_state, input_temp)
begin   

case (c_state) is

when RESET_ST               =>
led <= std_logic_vector (input_temp);

when S1                     =>
led <= std_logic_vector (input_temp);
when others                 =>
led                         <= (others => '1');

end case;
end process OUTPUT_BLOCK;


end Behavioral;

【问题讨论】:

  • 我会修改 input_temp 信号的调节方式。现在它处于一个组合过程中,其中 input_temp 不在敏感度列表中。此外, input_temp 未在“其他”状态下定义,因此您暗示了一个锁存器。你想要的是一个移位寄存器,顾名思义,input_temp 应该以顺序(时钟)过程为条件。

标签: vhdl fsm


【解决方案1】:

有两个立即可见的错误。

第一个计数器没有声明(注释掉,很简单)。

其次,一旦进入 S1 n_state

我想 Brian Drummond 现在会告诉您为您的 FSM 使用一个流程。本质上 input_temp 应该更改为带有存储的东西并移入时钟进程。

您可能会注意到,当 input_temp 变为静态(全为“0”)时,也没有任何东西可以检测。

附录

来自您的评论:

好的,如果我在敏感度列表中添加下一个状态,即 n_state, 它会起作用吗?

没有。如果你看上面的波形,n_state 总是包含 S1。

其次,是的,当它全为 0 时,我什么都看不到, 但是变速部分呢?

最终,一旦达到 input_temp(7),一个“1”就会丢失。

我明确定义了输出 每个州,我应该在这里限制吗?

你可以做三件事。 1. 让输出全部变为“0”,2. 重新循环“1”(约翰逊计数器)或 3. 停止并显示一些 LED。

如果状态是一个热状态,那么新的 8 个状态可以分别驱动一个 LED。 – David Koontz 2 小时前

你:

你能给我举个例子吗?这将有助于我更多地理解

一般来说,这不是教授基本 VHDL 或数字设计技能的正确场所,当然不在评论线程中。它是询问和回答特定 VHDL 问题的场所。见How do I ask a good question?

你问:

请有人告诉我这里出了什么问题。

我回答了,包括一张照片。

就在这里,您可能会注意到上面的波形图像与您问题的第一段冲突:

它根本不移动,只有 LSB 发光,就是这样,我也减慢了时钟,使用 1.5Hz 时钟。

如果您在波形中注意到它恰好移动一次,而您的代码未修改(除了删除您在问题中编辑的未声明的counter 的分配,请参阅下面的第一条评论)。

您定义的是一个两态状态机,要么复位要么移位。它不起作用,因为它没有正确编写。本质上,它描述了当前左移并清空的预期移位寄存器(input_temp)。您的状态是异步复位的触发器,释放时只需切换到另一个状态并假定启用移位。

实现左移(或以相反顺序连接)的 8 位移位寄存器,并且可以通过连接到复位的同步负载(到“00000001”)来实现。 8 个时钟后全是 0。

定义了九种状态(每个 LED 点亮一个状态,一个所有 LED 熄灭的状态)您可以通过添加该状态触发器来添加第 10 个状态。您可以使用 10 个触发器来实现一个热状态机,8 个触发器仅用于移位寄存器或 9 个触发器包含 c_state(和复位保持)。

我可以假设为上述两段生成三种不同的架构,但我不打算这样做。

这是对代码更改最少的最简单的实现:

architecture foo of scan is

    type state is ( RESET_ST, S1 );
    signal n_state:    state;
    signal c_state:    state;
    -- signal input_temp:  unsigned (7 downto 0):= "00000001";
    signal shft_reg:   std_logic_vector (7 downto 1);

begin

state_assignment: 
    process (clk, reset)
        begin
            if reset = '1' then
                c_state <= RESET_ST;
                -- counter <= (others => '0');
                shft_reg <= (others => '0');
            elsif  clk'event and clk = '1' then
                c_state <= n_state;
                if c_state = RESET_ST then
                    shft_reg <= shft_reg (6 downto 1) & '1';
                elsif shft_reg /= "1000000" then
                    shft_reg <= shft_reg (6 downto 1) & '0';
                end if;
            end if;
    end process;

--input_block : 
NEXT_STATE:
    process (c_state) 
    begin
        case (c_state) is
            when RESET_ST =>  
                -- input_temp <= "00000001";
                n_state <= S1;
            when S1 =>
                -- input_temp <= input_temp (6 downto 0) & '0';
                n_state  <= S1;
            when others => 
                n_state  <= RESET_ST;
        end case;
    end process;

-- output_block:
--     process (c_state, input_temp)
--     begin
--         case (c_state) is
--             when RESET_ST =>
--                 led <= std_logic_vector (input_temp);
--             when S1 =>
--                 led <= std_logic_vector (input_temp);
--             when others  =>
--                 led <= (others => '1');
--             end case;
--     end process;

-- LED0_OUT:
--     led(0) <= '1' when c_state = RESET_ST else '0';
LEDOUT:  
    process (c_state, shft_reg)
    begin
        if c_state = RESET_ST then
            led(0) <= '1';
        else
            led(0) <= '0';
        end if;
        led (7 downto 1) <= shft_reg;  -- shft_reg(7 downto 1)
    end process;

end architecture foo;

library ieee;
use ieee.std_logic_1164.all;

entity scan_tb is
end entity;

architecture foo of scan_tb is
    signal clk:     std_logic := '0';
    signal reset:   std_logic := '1';
    signal led:     std_logic_vector ( 7 downto 0);
begin

DUT:
    entity work.scan 
        port map (
            clk => clk,
            led => led,
            reset => reset
        );

CLOCK:
    process
    begin
        wait for 0.33 sec;  -- one half clock period, 1.5 Hz
        clk <= not clk;
        if Now > 20 sec then
            wait;
        end if;
    end process;

STIMULUS:
    process
    begin
        wait until rising_edge(clk);
        wait for 0.33 sec;
        wait until rising_edge(clk);
        reset <= '0';
        wait;        
    end process;

end architecture;

波形如下:

请注意,波形中 LED 的基数已更改为二进制。

还要注意两个波形的第一部分匹配。我还添加了一个 shft_reg 状态识别器以在设置 led(7) 时冻结 shft_reg。

您还可以注意到有一个优化。第一个 LED 被驱动关闭 c_state,其余 7 个被驱动关闭 7 位移位寄存器 (shft_reg)。还要注意的是,只使用了 8 个触发器。

正如 sonicwave 在对您的问题的评论中指出的那样,您应该首先真正模拟这些东西,所以这里有一个简单的测试台。

这是模拟的,使用删除了包 numeric_std 的 use 子句的实体声明(shft_reg 是 std_logic_vector 类型)、新架构 foo 和使用 ghdl-0.31 的 scan_tb 的实体/架构对:

david_koontz@Macbook: ghdl -a scan.vhdl
david_koontz@Macbook: ghdl -e scan_tb
david_koontz@Macbook: ghdl -r scan_tb --wave=scan_tb.ghw

在运行 OS X 10.9.3 的 Mac 上,其中 scan_tb.ghw 是 ghdl 特定的波形转储文件格式,非常适合 VHDL。

现在,请不要再在 cmets 上向您最初提出的问题添加更多问题。您也可以在示例代码中注释掉对未声明信号计数器的分配,而不是对其进行编辑。它破坏了问题和答案之间的连续性。

进一步

状态分配过程可以在不评估c_state的情况下编写:

state_assignment: 
    process (clk, reset)
        begin
            if reset = '1' then
                c_state <= RESET_ST;
                -- counter <= (others => '0');
                shft_reg <= (others => '0');
            elsif  clk'event and clk = '1' then
                c_state <= n_state;
--                if c_state = RESET_ST then
                if shft_reg = "0000000" then
                    shft_reg <= shft_reg (6 downto 1) & '1';
                elsif shft_reg /= "1000000" then
                    shft_reg <= shft_reg (6 downto 1) & '0';
                end if;
            end if;
    end process;

它做同样的事情。

现在多评论一下:

state_assignment: 
    process (clk, reset)
        begin
            if reset = '1' then
                c_state <= RESET_ST;
                -- counter <= (others => '0');
                shft_reg <= (others => '0');
            elsif  clk'event and clk = '1' then
                c_state <= n_state;
--                if c_state = RESET_ST then
                if shft_reg = "0000000" then
                    shft_reg <= shft_reg (6 downto 1) & '1';
--                elsif shft_reg /= "1000000" then
                else
                    shft_reg <= shft_reg (6 downto 1) & '0';
                end if;
            end if;
    end process;

并在 LEDOUT 过程中做出同样的决定改变:

LEDOUT:  
    process (shft_reg)
    begin
        if shft_reg = "0000000" then
            led(0) <= '1';
        else
            led(0) <= '0';
        end if;
        led (7 downto 1) <= shft_reg;  -- shft_reg(7 downto 1)
    end process;

您可以让扫描 LED 继续扫描:

我们已将 LED(0) 切换为不依赖其他 shft_reg 位置设置为“1”(不是“0”)。

【讨论】:

  • 对不起那个计数器的东西,我忘了评论它,我没有使用任何东西。好的,如果我在敏感度列表中添加下一个状态,即 n_state,它会起作用吗?其次,是的,当它全为 0 时,我什么都看不到,但是变速部分呢?我为每个状态明确定义了输出,我应该在这里设置限制吗?
  • a) 不,敏感度列表中的 n_state 不会做任何事情 b) 全部移零仍然是全零。您可以考虑显示每个 LED 的状态,因此总共有 10 个状态。如果状态是一个热状态,那么新的 8 个状态可以分别驱动一个 LED。
  • 这将定义一个 Johnson 计数器。
  • 你能给我举个例子吗?这将有助于我更多地理解
猜你喜欢
  • 2011-12-30
  • 2010-09-20
  • 1970-01-01
  • 1970-01-01
  • 2015-07-24
  • 1970-01-01
  • 2022-10-12
  • 2018-10-15
相关资源
最近更新 更多