[英]How do I correctly implement a Finite-State Machine into VHDL without taking in multiple inputs from Basysy3 FPGA
我是 VHDL 的新手,我正在嘗試將以下狀態機實現到 VHDL(下面提供的狀態圖)中。 當我按下 Basys3 FPGA 板上的按鈕(P 輸入)時,輸出是隨機狀態。 我懷疑這是因為時鍾在單次按下期間經歷了許多周期,因此從單次按下時接收了 1 個以上的輸入,但我不確定。 有什么我可以做的來解決這個問題。 我希望能夠按下按鈕 P 並且狀態一次改變一個。
library IEEE;
USE ieee.std_logic_1164.all;
ENTITY trasher is
PORT (
clock : IN STD_LOGIC;
P : IN STD_LOGIC;
reset : IN STD_LOGIC;
LED3, LED1,LED2,LED0 : OUT STD_LOGIC);
END ENTITY;
-- Architecture definition for the SimpleFSM entity
Architecture RTL of trasher is
TYPE State_type IS (A, B, C, D); -- Define the states
SIGNAL State : State_Type; -- Create a signal that uses
-- the different states
BEGIN
PROCESS (clock, reset)
BEGIN
IF (reset = '1') THEN -- upon reset, set the state to A
State <= A;
ELSIF rising_edge(clock) THEN -- if there is a rising edge of the
-- clock, then do the stuff below
-- The CASE statement checks the value of the State variable,
-- and based on the value and any other control signals, changes
-- to a new state.
CASE State IS
-- If the current state is A and P is set to 1, then the
-- next state is B
WHEN A =>
IF P='1' THEN
State <= B;
END IF;
-- If the current state is B and P is set to 1, then the
-- next state is C
WHEN B =>
IF P='1' THEN
State <= C;
END IF;
-- If the current state is C and P is set to 1, then the
-- next state is D
WHEN C =>
IF P='1' THEN
State <= D;
END IF;
-- If the current state is D and P is set to 1, then the
-- next state is B.
-- If the current state is D and P is set to 0, then the
-- next state is A.
WHEN D=>
IF P='1' THEN
State <= B;
ELSE
State <= A;
END IF;
WHEN others =>
State <= A;
END CASE;
END IF;
END PROCESS;
-- Decode the current state to create the output
-- if the current state is D, R is 1 otherwise R is 0
LED0 <= '1' WHEN State=A ELSE '0';
LED1 <= '1' WHEN State=B ELSE '0';
LED2 <= '1' WHEN State=C ELSE '0';
LED3 <= '1' WHEN State=D ELSE '0';
END rtl;
不要直接使用來自按鈕的輸入。 您需要饋送狀態機的是P
的上升沿檢測器的輸出,而不是P
本身。
此外, P
與您的主時鍾不同步,因此存在亞穩態風險。 最后但並非最不重要的是,如果它反彈,您將獲得多個值更改,而不僅僅是一個。 為了解決亞穩定性問題,您需要一個重新同步器,它只是一個移位寄存器。 您還可以使用它來生成一個中間信號,該信號僅在按下按鈕時的一個時鍾周期內被斷言為高電平,即狀態機所需的上升沿檢測器。 3 階段示例:
signal sync: std_ulogic_vector(0 to 2);
signal button_pressed: std_ulogic;
...
process(clock, reset)
begin
if reset = '1' then
sync <= (others => '0');
elsif rising_edge(clock) then
sync <= P & sync(0 to 1);
end if;
end process;
button_pressed <= sync(1) and (not sync(2));
sync
第 1 階段和第 2 階段可以安全使用,因為它們已經重新同步(假設 2 個階段足以滿足您的目標技術和平均故障間隔時間;如果您不了解這一點,請閱讀有關元穩定性的內容)。
當按下按鈕時,它們會sync
移動。 在兩個時鍾周期后, sync = "110"
所以button_pressed
被置為高電平。 一個時鍾周期后, sync = "111"
並且button_pressed
被取消斷言。 因此, button_pressed
是一個只有一個時鍾周期的指示器,表明按鈕被按下。 您可以將其用作狀態機的輸入。
第二個問題來自按鈕的工作方式。 如果您的原型板還沒有消除其按鈕的抖動,那么當按下按鈕時,您的P
輸入會在 0 和 1 之間振盪數次,然后穩定為 1。釋放按鈕時也是如此。 由於有時情況並非如此,因此在實施去抖器之前進行一些測試。 例如,計算button_pressed
被置為高電平的次數並將其發送到您的 LED:
signal cnt: u_unsigned(3 downto 0);
...
process(clock, reset)
begin
if reset = '1' then
cnt <= (others => '0');
elsif rising_edge(clock) then
cnt <= cnt + button_pressed;
end if;
end process;
LED0 <= std_logic(cnt(0));
LED1 <= std_logic(cnt(1));
LED2 <= std_logic(cnt(2));
LED3 <= std_logic(cnt(3));
如果您的按鈕彈跳,您有時應該看到的不僅僅是增量。 是時候搜索一些關於去抖動的信息,並在需要時提出一個新問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.