Переключатели состояний в FSM

У меня есть простая доска с 6 кнопками, состоящая из 3 столбцов и 2 строк. Я хотел бы обнаружить нажатую кнопку. Мой код ниже работает с этим fsm:

  scan_fsm : process (reset, clk)
  begin  -- process key_scanner

     if reset = '1' then 
            Send <= '0';
            fsm_state <= start;
            scannel_val <= "0000";

    elsif clk'event and clk = '1' then

      if state_inc = '1' then

        scan_complete <= '0';

        case fsm_state is

          when start =>
               Send <= '0';
            scannel_val <= "0000";
            my_switch   <= "001";
            fsm_state <= state1;

          when state1 => 
            case bcd_val is
              when "01" =>
                    Send <= '1';
                    scannel_val <= "0001";
              when "10" =>
                    Send <= '1';
                    scannel_val <= "0010"; -- Value 2 
              when others =>
                    scannel_val <= "0000";
                    Send <= '0';
            end case;
            my_switch   <= "010";
            fsm_state <= state2;

          when state2 => 
            case bcd_val is
              when "01" => 
                  Send <= '1';
                  scannel_val <= "0011"; 
              when "10" => 
                  Send <= '1';
                  scannel_val <= x"0100";  -- Value 4
              when others => 
                    scannel_val <= "0000";
                    Send <= '0'; 
            end case;
            my_switch   <= "100";
            fsm_state <= state3;

          when state3 => 
            case bcd_val is
              when "01" => 
                    Send <= '1';
                    scannel_val <= "0101"; 
              when "10" => 
                    Send <= '1';
                    scannel_val <= "0110";
              when others => 
                    scannel_val <= "0000";
                    Send <= '0'; 
            end case;
                my_switch   <= "001";
            fsm_state <= state1;
            scan_complete <= '1';

           when others => scannel_val <= "0000";
        end case;

      end if;
    end if;
  end process scan_fsm;

У меня есть 4 состояния, начало и состояние для каждого столбца. Я хотел бы улучшить свою плату и предотвратить сбои. Я хотел бы добавить функции, например, если 2 кнопки нажаты одновременно, я должен получить первое значение, которое достигло нескольких миллисекунд или наносекунд перед другим. Также я хотел бы предотвратить чтение второго значения или третьего, когда уже нажата кнопка.

Таким образом, независимо от того, сколько кнопок нажато, должно быть прочитано только одно значение. Я думал о добавлении 5-го состояния, бездействия, когда это происходит, но как мне выйти из бездействия?

Вместо простоя я также могу переключиться в состояние «старт», но тогда это сделает сигнал send«0», который будет ложным, если кнопка уже нажата. И сколько процессов в этом FSM? Что такое процесс в VHDL? Это 3; сброс, clk и state_inc? statce_inc становится "1" каждые 200 Гц с помощью счетчика. Я добавил код устранения дребезга, который нашел в Интернете, но не помогает :( У кого-нибудь есть предложение по устранению дребезга?

Еще одна проблема: на самом деле я хотел бы избавиться от состояния start, единственная причина, по которой оно у меня есть, заключается в том, что я должен назначить my_switchзначение "001"before state1. В моей первой реализации я назначал my_switchin "001"и state1in и "010"in . В этой реализации, поскольку моя клавиатураstate2"100"state3

______
|1|2|3|
|4|5|6|

Когда я нажимал 2, отображалось 1, когда я нажимал 3, отображалось 2. Я думал о Cpp/Java, но ошибся... затем я добавил фиктивное состояние, startчтобы установить его my_switchперед началом реального сканирования... Так что, если я смогу решить эту проблему, я также смогу сохранить состояние! Предложения приветствуются! Я решил это, введя первое сканирование без установленного значения. У вас есть идеи получше?

Что такое bcd_val? Какие сигналы являются входными данными столбца и строки?
@StaceyAnne my_switch(столбец) - это выходной сигнал, а bcd_val(строка) - вход, поэтому bcd_valдолжно быть 2 бита, извините за это, сейчас я обновляю код
Для чего нужен state_inc?
@StaceyAnne Большое спасибо за ответ! state_inc — это сигнал включения, он равен «1» каждые 200 Гц.
Мне любопытно узнать, почему вы периодически включаете конечный автомат, он должен работать постоянно.
@StaceyAnne мой код без включения не работал, но настоящая идея заключается в том, чтобы замедлить конечный автомат, чтобы предотвратить дребезг. Я также немного расширил вопрос, не могли бы вы взглянуть, пожалуйста?

Ответы (1)

Что вы можете сделать, так это создать состояние ожидания, и когда вы обнаружите нажатие кнопки, вы переключитесь прямо в состояние ожидания. Затем у вас может быть счетчик в режиме ожидания, который некоторое время ждет, прежде чем вы снова начнете сканировать кнопки.

Например:

-- include numeric std
signal idle_counter : unsigned(31 downto 0);

      ...

      when state3 => 
        case bcd_val is
          when "01" => 
                Send <= '1';
                scannel_val <= "0101"; 
                fsm_state <= idle;   -- switch to idle
          when "10" => 
                Send <= '1';
                scannel_val <= "0110";
                fsm_state <= idle;   -- switch to idle
          when others => 
                scannel_val <= "0000";
                Send <= '0'; 
                fsm_state <= state1;   -- carry on scanning
        end case;
        idle_counter <= (others => '0');
        ...
      when idle =>
        if (idle_counter < some_timeout) then  -- some_timeout is how long you want to wait (in clock cycles)
           idle_counter <= idle_counter + "1"; -- increment counter
           fsm_state <= idle;                  -- stay here
        else
           idle_counter <= (others => '0');    -- reset counter
           fsm_state <= state1;                -- go back into checking
        end
        --scannel_val is valid here, so you can do something with it if you'd like.
        ...
      when others => scannel_val <= "0000";

В этом коде, который вы разместили, есть один процесс.

Это начинается с

scan_fsm : process (reset, clk) <= Sensitivity list
begin  -- process key_scanner

и заканчивается

end process scan_fsm;

Часы и сброс являются частью списка чувствительности. Это означает, что этот код будет запускаться только при изменении часов или сброса.

Устранение дребезга может быть выполнено в отдельном процессе. По сути, вы хотите убедиться, что кнопка была нажата в течение нескольких микросекунд, прежде чем она сработает. Что мы хотим сделать, так это сохранить значение ввода в течение нескольких тактов. Затем зарегистрируйте 1 только тогда, когда история была постоянно 1 в течение последних 32 тактов.

Пример:

-- these are our row inputs (to become bdc_val)
signal row1 : in std_logic; 
signal row2 : in std_logic;

...
-- this is our history vector
signal row1_z : std_logic_vector(31 downto 0);
signal row2_z : std_logic_vector(31 downto 0);

-- debounced signal
signal bcd_val : std_logic_vector(1 downto 0);

-- a whole vector of ones for convenience
signal ones    : std_logic_vector(31 downto 0);
...

ones <= (others => '1');

-- generate our histories
gen_z : process (reset, clk)
begin  
  if (reset = '1') then
    row1_z <= (others => '0');
    row2_z <= (others => '0');
    bcd_val <= (others => '0');
  elsif (rising_edge(clk)) then
    row1_z(31 downto 1) <= row1_z(30 downto 0); -- shift everything up 1
    row1_z(0) <= row1;                          -- save the most recent input
    row2_z(31 downto 1) <= row2_z(30 downto 0); -- shift everything up 1
    row2_z(0) <= row2;                          -- save the most recent input

    -- we only want bcd_val to be 1 when the entire row history for the past 32 cc is 1
    if (row1_z = ones) then
      bcd_val(0) <= '1';
    else 
      bcd_val(0) <= '0';
    end

    if (row2_z = ones) then
      bcd_val(1) <= '1';
    else 
      bcd_val(1) <= '0';
    end
  end
end
У меня есть еще один вопрос, когда я нажимаю 3 и 1 одновременно, scanned_valполучает 0, когда я нажимаю 3 и 6, он также получает 0, поэтому одни и те же клавиши столбца и строки получают 0, когда они оба нажимаются одновременно, потому что я when others => scannel_val <= "0000";думаю результат также должен быть нулевым, когда я нажимаю 3 и 4 одновременно, потому что столбец получает 001, а 100 затем становится 101, что следует рассматривать как «другие», не так ли? Или я хотел бы изменить код вместо того, чтобы обнулять значения при одновременном нажатии из одного и того же столбца или строки, сохранить первое нажатое значение?