在Nexys2上运行FSM时遇到麻烦

时间:2014-06-22 06:29:55

标签: vhdl fsm

我正在尝试运行一个扫描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;

1 个答案:

答案 0 :(得分:1)

有两个立即可见的错误。

未宣布第一个计数器(注释掉,很容易)。

第二,一旦进入S1 n_state&lt; = S1,换句话说,你去S1并坐在那里。这样做的结果是INPUT_BLOCK进程没有触发事件 - 灵敏度只包含c_state而且c_state没有进一步的变化。

scan_tb, a single state transition

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

您可以注意到,当input_temp变为静态(所有&#39; 0&#39; s)时,无法检测到任何内容。

<强>附录

来自你的评论:

  

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

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

  

其次是的,当它全部发生时,我什么也看不见,   但转变部分呢?

最终那个&#39; 1&#39;一旦达到input_temp(7)就会迷路。

  

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

你可以做三件事。 1.让输出全部转到&#39; 0,2。再循环&#39; 1&#39; (约翰逊柜台)或3.停下来显示一些LED。

  

如果状态很热,新的8个州可以分别驱动LED。 - David Koontz 2小时前

你:

  

你能不能给我一个例子或什么?这将有助于我更多地理解

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

你问:

  

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

我回答,包括一张照片。

就在这里你可以注意到上面的波形图与你问题的第一段相冲突:

  

它完全没有移动只有LSB发光,就是这样,我也使用1.5Hz时钟减慢时钟速度。

如果你在波形中注意它只改变了一次,你的代码没有修改(除了删除你编辑过的未申报counter的作业,请参阅下面的第一条评论)。

您定义的是两个状态机重置或移位。它不起作用,因为它没有正确编写。它必不可少地描述了当前向左移位和清空的预期移位寄存器(input_temp)。你的状态是一个触发器运行异步复位,当释放时只是切换到另一个状态,并据说启用了移位。

实现向左移位(或以相反顺序连接)的8位移位寄存器,并且可以通过连接到复位的同步加载(到&#34; 00000001&#34;)来实现。 8个时钟之后它全部都是

定义了九个状态(每个LED点亮一个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;

以下是波形的样子:

scan_tb2 corrected

请注意,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是一种非常适合VHDL的ghdl特定波形转储文件格式。

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

<强>进一步

可以在不评估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继续扫描:

scan with continuous recirculate

我们切换LED(0)依赖于没有其他shft_reg位置被设置为&#39; 1&#39; (不是&#39; 0&#39;)。