Ich habe ein einfaches Board mit 6 Knöpfen, bestehend aus 3 Spalten und 2 Reihen Ich möchte den gedrückten Knopf erkennen. Mein Code unten funktioniert mit diesem 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;
Ich habe 4 Zustände, Start und einen Zustand für jede Spalte. Ich möchte mein Board verbessern und Störungen vorbeugen. Ich möchte Funktionen hinzufügen, z. B. wenn 2 Tasten gleichzeitig gedrückt werden, sollte ich den ersten Wert erhalten, der einige Millisekunden oder Nanosekunden vor dem anderen erreicht. Außerdem möchte ich verhindern, dass ein zweiter Wert gelesen wird oder ein dritter, wenn bereits eine Taste gedrückt wird.
Es sollte also immer nur ein Wert gelesen werden, egal wie viele Tasten gedrückt werden. Ich habe darüber nachgedacht, einen fünften Zustand hinzuzufügen, Leerlauf, wenn dies auftritt, aber wie komme ich dann aus dem Leerlauf heraus?
Statt Leerlauf kann ich auch in den Zustand "Start" wechseln, aber das würde dann das send
Signal "0" machen, was falsch wäre, wenn bereits eine Taste gedrückt wird. Auch wie viele Prozesse sind in diesem FSM? Was ist ein Prozess in VHDL? Ist es 3; zurücksetzen, clk und state_inc? statce_inc wird mit Hilfe eines Zählers alle 200Hz "1". Ich habe einen Entprellungscode hinzugefügt, den ich aus dem Internet gefunden habe, aber er hilft nicht :( Hat jemand einen Entprellungsvorschlag?
start
Ein weiteres Problem, ich möchte den Zustand eigentlich loswerden , der einzige Grund, warum ich ihn habe, ist, weil ich ihn vorher my_switch
zuweisen sollte . In meiner ersten Implementierung habe ich in und in und in zugewiesen . In dieser Umsetzung liegt mein Tastenfeld"001"
state1
my_switch
"001"
state1
"010"
state2
"100"
state3
______
|1|2|3|
|4|5|6|
Wenn ich 2 drückte, wurde 1 angezeigt, wenn ich 3 drückte, wurde 2 angezeigt. Ich habe an Cpp/Java gedacht, aber ich habe mich geirrt ... dann habe ich einen Dummy-Zustand hinzugefügt, start
nur um ihn my_switch
vor dem eigentlichen Scannen festzulegen ... Wenn ich das also lösen kann, kann ich auch einen Zustand speichern! Vorschläge sind willkommen! Ich habe das gelöst, indem ich den ersten Scan ohne gesetzten Wert eingegeben habe. Haben Sie bessere Ideen?
Was Sie tun können, ist einen Ruhezustand zu schaffen, und wenn Sie einen Tastendruck erkennen, schalten Sie direkt in den Ruhezustand. Dann können Sie einen Zähler im Leerlauf haben, der eine Weile wartet, bevor Sie erneut mit dem Scannen von Schaltflächen beginnen.
Zum Beispiel:
-- 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";
Es gibt einen Prozess in diesem Code, den Sie gepostet haben.
Es beginnt mit
scan_fsm : process (reset, clk) <= Sensitivity list
begin -- process key_scanner
und endet mit
end process scan_fsm;
Die Uhr und das Zurücksetzen sind Teil der Empfindlichkeitsliste. Das bedeutet, dass dieser Code nur ausgelöst wird, wenn sich entweder die Uhr ändert oder sich ändert.
Das Entprellen kann in einem separaten Prozess erfolgen. Grundsätzlich möchten Sie sicherstellen, dass die Taste einige Mikrosekunden lang gedrückt wurde, bevor sie ausgelöst wird. Was wir tun möchten, ist den Wert des Eingangs für eine Anzahl von Taktzyklen zu speichern. Registrieren Sie dann nur dann eine 1, wenn die Historie für die letzten 32 Taktzyklen konstant 1 war.
Beispiel:
-- 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
wird 0 angezeigt, wenn ich 3 und 6 drücke, wird auch 0 angezeigt, sodass dieselben Spalten- und Zeilentasten 0 erhalten, wenn sie beide gleichzeitig gedrückt werden, weil ich when others => scannel_val <= "0000";
denke Das Ergebnis sollte auch Null sein, wenn ich gleichzeitig 3 und 4 drücke, weil die Spalte 001 erhält und 100 dann zu 101 wird, was als "andere" betrachtet werden sollte, nicht wahr? Oder ich möchte den Code ändern, anstatt die Werte auf Null zu setzen, wenn sie gleichzeitig aus derselben Spalte oder Zeile gedrückt werden, und den ersten gedrückten Wert beibehalten?
Stanri
Anarkie
my_switch
(Spalte) ist ein Ausgangssignal undbcd_val
(Zeile) ist ein Eingang,bcd_val
sollte also 2 Bit lang sein. Entschuldigung, dass ich jetzt den Code aktualisiereStanri
Anarkie
Stanri
Anarkie