2014-03-28 52 views
1

我在用Verilog實現有限狀態機的過程是,我遇到了一個問題。但是,我知道問題是什麼,但我不知道如何解決問題。在這個FSM機的狀態變化太快由於與時鐘的問題,更新當前狀態

這是我當前的代碼:

module moore_SM(clk, rstn, btn, z, rstLED, state); 

    //Port Assignments 
    input clk, rstn; 
    input [2:0] btn; 
    output z; 
    output reg rstLED; 
    output reg [5:0] state; 

    //Internal Port Assignments 
    reg [1:0] w, x; //NOTE: This is typically the input in FSM, 
        //but it is internal because there is a conversion from btn to w. 
    reg [2:0] y, Y; //Present state and next state respectively 
    reg [2:0] pstBtn; 
    reg [31:0] cnt; 

    //Define some parameters 
     //Input Type (i.e. A, B or C) 
     parameter [1:0] A = 2'b00, B = 2'b01, C = 2'b11, DC = 2'b10; //DC => don't care - shouldn't affect FSM 

     //State (i.e. S1, S2, S3, S4, S5 or S6) 
     parameter [2:0] S1 = 3'b000, S2 = 3'b001, S3 = 3'b010, S4 = 3'b011, S5 = 3'b100, S6 = 3'b101; 

    initial begin 
     state = 0; 
    end 

    //Determine which button is active 
    always @(*) 
     begin 
      case(btn) 
       3'b110: begin w = A; end 
       3'b101: begin w = B; end 
       3'b011: begin w = C; end 
      // default: w = DC; 
      endcase 
     end 

    //Define the next state and output combinational circuits 
    always @(w,y) 
    begin 
     case(y) 

      S1: begin 
        state = 6'b000001; 
        if(w == A) begin Y = S2; end 
        else begin Y = S1; end 
       end 

      S2: begin 
        state = 6'b000010; 
        if(w == B) begin Y = S3; end 
        else begin if(w == A) begin Y = S2; end 
        else Y = S1; end 
       end 

      S3: begin 
        state = 6'b000100; 
        if(w == A) begin Y = S2; end 
        else begin if(w == B) begin Y = S4; end 
        else Y = S1; end 
       end 

      S4: begin 
        state = 6'b001000; 
        if(w == A) begin Y = S5; end 
        else begin Y = S1; end 
       end 

      S5: begin 
        state = 6'b010000; 
        if(w == A) begin Y = S2; end 
        else begin if(w == B) begin Y = S3; end 
        else Y = S6; end 
       end 

      S6: begin 
        state = 6'b100000; 
        if(w == A) begin Y = S2; end 
        else begin Y = S1; end 
       end 

      //default: Y = 3'b111; 

     endcase 

     end 

    //assign z = (Y == S2); 

    //Define the sequential block 
    always @(posedge clk) 
    begin 
     y <= Y; 
    end 

endmodule 

此代碼應該識別模式ABBAC。我相信這個邏輯可以達到這個目的。

但是,我遇到了一個問題。當按下三個按鈕中的一個時,第一個總是阻止 - always @(*) - 執行並評估更改。該按鈕的狀態被編碼並保存到w.同時,下一個始終阻止 - always @(w,y) - 感知更改並確定要駐留在哪個狀態。如我所料,如果我發送輸入A,機器從S1移動到S2

現在如果我發送輸入B,機器將回到狀態S1。在我改變了一些事情之後,我確定了我認爲是問題的東西。注意最後總是塊:always @(posedge clk).這總是阻止不斷更新目前的狀態,y.當我按下一個按鈕,我認爲正在發生的事情是,第二always塊,always @(w,y),被接收在50MHz更新y(在我的情況),其中顯然比我按下並釋放按鈕要快得多。假設我按下按鈕B而在狀態S2,狀態變化快於S3S4再到S1因爲持續更新的。

這麼說,我遇到一些麻煩來了一個辦法來解決這個問題。我基本上需要一些方法來改變每個按鈕按下只有一個狀態。

請注意,我主要在實驗板上測試此代碼。我寫了一個測試臺,但仿真看起來與我在設計板上看到的不一樣。如果有人想看看測試平臺的代碼,我張貼如下:

`timescale 1ns/1ns 
module moore_SM_TB(); 
    reg clk; 
    reg [2:0] btn; 
    wire [5:0] state; 
    wire z; 
    wire rstLED; 

    initial begin 
    clk = 1; 
    #0 btn = 3'b111; 
    #50 btn = 3'b110; 
    #50 btn = 3'b111; 
    #50 btn = 3'b101; 
    #50 btn = 3'b111; 
    #50 btn = 3'b011; 
    #50 btn = 3'b111; 
end 

always begin 
    #20 clk = ~clk;  
end 

    //MUT 
    moore_SM MUT (clk, 0, btn, z, rstLED, state); 

endmodule 

注:我相信該解決方案將最終涉及修改按鍵的處理方式。當我釋放一個按鈕時,這也會被註冊爲一個改變。因此,我必須將默認情況註釋掉,因爲它也會弄亂機器處於哪種狀態。

更新:我寫了一個縮減版本的FSM,我在上面貼出來嘗試和調試代碼。它試圖檢測序列AB。

module moore_SM(clk, btn, rstN, state, rstLED); 
//Port assignments 
input clk; 
input rstN; 
input [2:0] btn; 
output reg rstLED; 
output reg [5:0] state; 

//Internal Port Assignments 
reg [1:0] w; 
reg [2:0] y, Y; 
reg [2:0] pstBtn; 

//Define some parameters 
parameter [1:0] A = 2'b00, B = 2'b01, C = 2'b11, DC = 2'b10; 
parameter [2:0] S1 = 3'b000, S2 = 3'b001, S3 = 3'b010, S4 = 3'b011, S5 = 3'b100, S6 = 3'b101; 

//Initialize some values to prevent Quartus from doing 
initial 
    begin 
     y = S1; 
     Y = y; 
     state = 0; 
     rstLED = 0; 
    end 

always @(*) 
    begin 

     if(btn == pstBtn) begin w = DC; end 

     else begin 
      case(btn) 
       3'b110: w = A; 
       3'b101: w = B; 
       3'b011: w = C; 
       default: w = DC; 
      endcase 
     end 

    end 

always @(*) 
    begin 
     case(y) 
      S1: begin 
        state = 6'b000001; 
        if(w == A) begin Y = S2; end 
        else begin Y = S1; end 
       end 

      S2: begin 
        state = 6'b000010; 
        if(w == B) begin Y = S3; end 
        if(w == DC) begin Y = S2; end 
        else begin Y = S1; end 
       end 

      S3: begin 
        state = 6'b000100; 
        if(w == DC) begin Y = S3; end 
        else begin Y = S1; end 
       end 
      default: begin state = 6'b100000; Y = S1; end 
     endcase 
    end 



//Update state and check for reset signal 
always @(posedge clk, negedge rstN) 
    begin 
     pstBtn <= btn; 

     if(rstN == 0) begin y <= S1; rstLED <= 1; end 
     else begin y <= Y; rstLED <= 0; end 
    end 

endmodule 

請注意,我試圖「取樣」在最後總是塊的按鈕狀態。過去我使用過這種方法,但在這裏似乎並不奏效。每當我按下一個按鈕,狀態就不會改變。我想知道現在是否是時機問題。

+1

狀態應該改變時鐘邊緣,不combinatorialy – Morgan

+0

我再次查看我的代碼後,我相信這是它在做什麼。組合模塊定義下一個狀態「Y」,然後在時鐘邊沿更新當前狀態「y」。 – Mlagma

+0

不,這本書顯示'Y'(爲了清晰起見,我們通常稱之爲* nextState *或* next_state *)正在發生組合變化。然而,* nextState *值只能在下一個時鐘邊註冊:'always @(posedge clk)... y <= Y;' – smci

回答

3

如果按鈕輸入即將一個開關,而不是測試激勵它將是異步的,因此應該通過2元穩定性觸發器放。要改變每個按鈕的狀態,請按下創建邊緣檢測。

邊緣檢測將創建1個時鐘週期寬脈衝,導致每按1個過渡。

reg [2:0] btn0_meta; 
always @(posedge clk or negedge rstN) begin 
    if (~rstN) begin 
    btn0_meta <= 'b0; 
    end 
    else begin 
    btn0_meta <= {btn0_meta[1:0], btn[0]}; 
    end 
end 

reg btn0_posedge; 
always @* begin 
    btn0_posedge = btn0_meta[1] & ~btn_meta[2]; 
end 

對所有按鈕輸入執行此操作,並在狀態機中使用btnX_posedge。

+0

謝謝,我使用這個背後的一般,它工作得很好。 – Mlagma

+0

「一般*想法」 – Mlagma

+0

@Mlagma很高興我們可以提供幫助。對於嘈雜的按鈕,您可能也想查看去除。基本上檢查按鈕的改變狀態持續了一定的時間,這減少了幾個按鈕按下時檢測到開關觸點機械跳動的機會。儘管如此,不少FPGA還是會爲您提供幫助。 – Morgan