У меня есть простая доска с 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_switch
in "001"
и state1
in и "010"
in . В этой реализации, поскольку моя клавиатураstate2
"100"
state3
______
|1|2|3|
|4|5|6|
Когда я нажимал 2, отображалось 1, когда я нажимал 3, отображалось 2. Я думал о Cpp/Java, но ошибся... затем я добавил фиктивное состояние, start
чтобы установить его my_switch
перед началом реального сканирования... Так что, если я смогу решить эту проблему, я также смогу сохранить состояние! Предложения приветствуются! Я решил это, введя первое сканирование без установленного значения. У вас есть идеи получше?
Что вы можете сделать, так это создать состояние ожидания, и когда вы обнаружите нажатие кнопки, вы переключитесь прямо в состояние ожидания. Затем у вас может быть счетчик в режиме ожидания, который некоторое время ждет, прежде чем вы снова начнете сканировать кнопки.
Например:
-- 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
scanned_val
получает 0, когда я нажимаю 3 и 6, он также получает 0, поэтому одни и те же клавиши столбца и строки получают 0, когда они оба нажимаются одновременно, потому что я when others => scannel_val <= "0000";
думаю результат также должен быть нулевым, когда я нажимаю 3 и 4 одновременно, потому что столбец получает 001, а 100 затем становится 101, что следует рассматривать как «другие», не так ли? Или я хотел бы изменить код вместо того, чтобы обнулять значения при одновременном нажатии из одного и того же столбца или строки, сохранить первое нажатое значение?
станри
Анарки
my_switch
(столбец) - это выходной сигнал, аbcd_val
(строка) - вход, поэтомуbcd_val
должно быть 2 бита, извините за это, сейчас я обновляю кодстанри
Анарки
станри
Анарки