国机;为什么只有最后一个州工作?

时间:2014-05-02 18:36:41

标签: vhdl state-machine fsm case-when

我有一个状态机,有6个状态(3个主要状态)。只有最后一个状态正在起作用,但前两个状态不起作用(满分为3个)。只有最后一个状态才有效。我发现了问题,当我移除它的去抖电路时,我需要去抖动电路。我从互联网上得到了去抖电路。如果有人可以提供帮助,我会很高兴。

 type SM_STATES is (state_column_1, scan_col_1, state_column_2, scan_col_2,
                          state_column_3, scan_col_3);
 signal my_state     : SM_STATES                   := state_column_1;

以下是状态机:

scanner_sm : process (clk)
begin  -- process key_scanner
  if clk'event and clk = '1' then

  if state_inc = '1' then -- clock divider finished counting down 100000

    -- reset scan_complete
    scan_complete <= '0';

case my_state is

  when state_column_1 =>
    scanned_val  <= (others => '0');
    original_col   <= "110";
    my_state <= scan_col_1;

  when scan_col_1 =>
    case bcd_val is
      when "1110" => scanned_val <= "1100100";  -- 1 wrong
      when "1101" => scanned_val <= "1100010";  -- 2 wrong
      when others => scanned_val <= "0010000";
    end case;
    my_state <= state_column_2;

  when state_column_2 =>
    original_col   <= "011";
    my_state <= scan_col_2;

  when scan_col_2 =>
    case bcd_val is
      when "1110" => scanned_val <= "1011011";  -- 5 wrong
      when "1101" => scanned_val <= "1011111";  -- 6 wrong
      when others => scanned_val <= "0000000";
    end case;
    my_state <= state_column_3;

  when state_column_3 =>
    original_col   <= "101";
    my_state <= scan_col_3;

  when scan_col_3 => -- Reading S1 // The only working state
    case bcd_val is
      when "1110" => scanned_val <= "1100000";  -- 9/ 1
      when "1101" => scanned_val <= "0111110";  -- X/ 2
      when others => scanned_val <= "0000000";
    end case;
    my_state <= state_column_1; -- ************ Error might be here
    scan_complete <= '1'; -- ********** Error might be here

  when others => scanned_val <= "0000000";
end case;

      end if;
  end if;
end process scanner_sm;

debounce: process (CLK) is 
begin 
 if (CLK'event and CLK = '1') then  
  Q0 <= scannel_val; 

  Q1 <= Q0; 

  Q2 <= Q1; 

 end if; 

end process; 

Final_val <= Q0 and Q1 and (not Q2);

end Behavioral; 

2 个答案:

答案 0 :(得分:2)

到目前为止,您的代码不完整 - 您可以在案例陈述中直接分配由状态机评估的信号 my_state 。要理解这个问题,我们需要知道模拟器是如何工作的:

与实际硬件相比,模拟器必须在顺序事务中使用顺序CPU处理代码。这是通过在无限小的时间距离内反复遍历代码 - 所谓的Delta delay - 直到所有依赖关系都已解决,即不再发生任何变化。

请注意,在此迭代期间没有经过实际时间。在正确编写的设计中,模拟器现在等待直到下一个事件发生 - 通常是由时钟的滴答引起的,这再次重启了连续的迭代。

你的例子基本上类似于无限循环: my_state 的更改总是导致my_state的下一次更改,因此模拟器永远不会达到一个值 - 直到它达到硬编码的迭代限制,这是偶然的在你的情况下是第三个州。

那么,如何解决这个问题呢?我们需要引入一个时钟,并且需要根据实际的模拟时间进行状态转换,通常是等待时钟事件。最佳实践是将组合和顺序部分分成两个不同的过程,如状态机的最小示例所示:

library ieee;
use ieee.std_logic_1164.all;

entity foo is

end entity foo;

architecture bar of foo is
  type SM_STATES is (state_column_1, scan_col_1, state_column_2, scan_col_2, state_column_3, scan_col_3);
  signal my_state, my_state_next : SM_STATES;
  signal bcd_val                 : std_logic_vector(3 downto 0) := "1110";
  signal clk                     : std_logic                    := '1';
  signal nRST                    : std_logic                    := '0';
  signal scanned_val             : std_logic_vector(6 downto 0);
  signal original_col            : std_logic_vector(2 downto 0);
  signal scan_complete           : std_logic;
begin  -- architecture bar

  comb : process (my_state, bcd_val) is
  begin  -- process baz
    case my_state is

      when state_column_1 =>
        scanned_val   <= (others => '0');
        original_col  <= "110";
        my_state_next <= scan_col_1;

      when scan_col_1 =>
        case bcd_val is
          when "1110" => scanned_val <= "1100100";  -- 1 wrong
          when "1101" => scanned_val <= "1100010";  -- 2 wrong
          when others => scanned_val <= "0010000";
        end case;
        my_state_next <= state_column_2;

      when state_column_2 =>
        original_col  <= "011";
        my_state_next <= scan_col_2;

      when scan_col_2 =>
        case bcd_val is
          when "1110" => scanned_val <= "1011011";  -- 5 wrong
          when "1101" => scanned_val <= "1011111";  -- 6 wrong
          when others => scanned_val <= "0000000";
        end case;
        my_state_next <= state_column_3;

      when state_column_3 =>
        original_col  <= "101";
        my_state_next <= scan_col_3;

      when scan_col_3 =>                -- Reading S1 // The only working state
        case bcd_val is
          when "1110" => scanned_val <= "1100000";  -- 9/ 1
          when "1101" => scanned_val <= "0111110";  -- X/ 2
          when others => scanned_val <= "0000000";
        end case;
        my_state_next <= state_column_1;  -- ************ Error might be here
        scan_complete <= '1';           -- ********** Error might be here

      when others => scanned_val <= "0000000";
    end case;
  end process comb;

  process (clk, nRST) is
  begin  -- process
    if nRST = '0' then                  -- asynchronous reset (active low)
      my_state <= state_column_1;
    elsif clk'event and clk = '1' then  -- rising clock edge
      my_state <= my_state_next;
    end if;
  end process;

  -- this clock and reset signal would usually be supplied from the outside
  clk  <= not clk after 10 ns;
  nRST <= '1'     after 101 ns;
end architecture bar;

如果我们现在在模拟器中运行此文件,我们可以看到状态在每个时钟周期切换:

Simulation of the fixed code.

答案 1 :(得分:1)

您可以将此视为基于迭代绑定的答案。

我实现了完整的状态机进程:

library ieee;
use ieee.std_logic_1164.all;

entity foo is

end entity foo;

architecture fum of foo is

    type SM_STATES is ( 
        state_column_1, scan_col_1, 
        state_column_2, scan_col_2, 
        state_column_3, scan_col_3
    );

    signal my_state:        SM_STATES;  -- defaults to SM_STATES'LEFT

    signal state_inc:       std_logic := '0';

    signal bcd_val:         std_logic_vector(3 downto 0) := "1110";
    signal clk:             std_logic := '0';

    signal scanned_val:     std_logic_vector(6 downto 0);
    signal original_col:    std_logic_vector(2 downto 0);
    signal scan_complete:   std_logic;

begin

scanner_sm: 
    process (clk)
    begin
        if clk'event and clk = '1' then

            if state_inc = '1' then

                scan_complete <= '0';

                case my_state is

                    when state_column_1 =>
                        scanned_val  <= (others => '0');
                        original_col   <= "110";
                        my_state <= scan_col_1;

                    when scan_col_1 =>
                        case bcd_val is
                            when "1110" => scanned_val <= "1100100";  -- 1 wrong
                            when "1101" => scanned_val <= "1100010";  -- 2 wrong
                            when others => scanned_val <= "0010000";
                        end case;
                        my_state <= state_column_2;

                    when state_column_2 =>
                        original_col   <= "011";
                        my_state <= scan_col_2;

                    when scan_col_2 =>
                        case bcd_val is
                            when "1110" => scanned_val <= "1011011";  -- 5 wrong
                            when "1101" => scanned_val <= "1011111";  -- 6 wrong
                            when others => scanned_val <= "0000000";
                        end case;
                        my_state <= state_column_3;

                    when state_column_3 =>
                        original_col   <= "101";
                        my_state <= scan_col_3;

                    when scan_col_3 => -- Reading S1 // The only working state
                        case bcd_val is
                            when "1110" => scanned_val <= "1100000";  -- 9/ 1
                            when "1101" => scanned_val <= "0111110";  -- X/ 2
                            when others => scanned_val <= "0000000";
                        end case;
                        my_state <= state_column_1; -- ************ Error might be here
                        scan_complete <= '1'; -- ********** Error might be here

                    when others => scanned_val <= "0000000";
                end case;

          end if;
      end if;
    end process scanner_sm;

CLOCK:
    process 
    begin
       wait for 10 ns;
       clk <= not clk;
       if Now > 200 ns then
           wait;
       end if;
    end process;

STIMULUS:
    process
    begin
        wait for 30 ns;
        state_inc <= '1';
        wait;
    end process;

end architecture;

你可以看到没有下一个状态。猜猜它的作用。

我在断言之前将state_inc延迟了一个时钟,以显示你应该重置的原因:

foo_tb waveform

您可以看到scan_complete,scans_val和original_col的状态在写入之前最初是未知的。你也可以重置my_state。

您可以从上面的模拟和迭代绑定中看到,您的状态机遍历所有六个状态。如果它被卡在某个地方,你会发现state_inc不会有效(并且它也不明显是什么使它从你的进程中变得无效)。

除了没有重置之外,你的状态机没有任何明显的错误, 问题似乎出现在其他地方或与状态边界操作有关,阻止了state_inc的发生。 < /强>

我希望您可能需要一个额外的状态来完成信号扫描并开始下一次扫描,否则任何state_inc仍然有效会导致下一轮状态转换。 (在scan_col3和state_column_1之间,与你的评论保持一致&#34; ************错误可能在这里&#34;)。

添加重置和仅持续一个时钟的附加状态(名称 - 完成?)可以通过以下方式完成:

 if state_inc = '1' or my_state = complete then

现在的地方

  if state_inc = '1' then

在转到state_column_1之前,这将给出对scan_complete做出反应的任何机会。您可以检查完整是否应该命名为start_or_complete,并且是第一个状态。

我对你的流程所做的唯一一件事就是更改缩进,以便更容易看到if语句中的所有内容都掉了。

(我们确实警告过您,我们希望看到您的模型更多)