1. 程式人生 > >fpga狀態機詳解

fpga狀態機詳解

循環 產生 attribute state begin 分享 hello view 如何

什麽是狀態機:狀態機通過不同的狀態遷移來完成特定的邏輯操作

狀態機的分類:Moore型狀態機和Mealy型狀態機

  1. Moore型:狀態機的變化只與當前的狀態有關
  2. Mealy型:狀態機的變化不僅與當前的狀態有關,還與輸入有關

如何創建狀態機:狀態機的創建可以分為一段式,兩段式和三段式

  1. 一段式:主要是講所有的狀態變化以及導致的輸出變化都寫在了一個always快中。

  2. 兩段式:將一些復位信號,clk信號單獨寫在一個always快中,其他的狀態變化,輸出值得變化寫在一個always快中。

  3. 三段式:將一些復位信號,clk信號單獨寫在一個always快中,其他的狀態遷移變化寫在一個always快中,對應狀態的輸出值得變化寫在一個always快中。

舉個例子:從循環輸入的字母中做連續檢測,當連續檢測到“hello”時,將led燈進行狀態的翻轉,繼續進行下一次的檢測。
技術分享圖片

  1. 一段式的編寫方式:
module  hello(
input clk,//系統時鐘信號  50mHz
input rst_n,//系統復位信號,低電平有效
input [7:0] data,//連續輸入的字母
output reg led//led燈
);

//設置需要改變的狀態
parameter    checkh  = 5‘b0000_1,
             checke  = 5‘b0001_0,
             checkla = 5‘b0010_0,
             checklb = 5‘b0100_0,
             checko = 5‘b1000_0;

reg [4:0]state;

always @(posedge clk or negedge rst_n)
    if(!rst_n)
        begin
            led <= 1‘b0;
            state <= checkh;
        end
    else 
        begin
            case (state)
                checkh:
                    if(data == "h") state <= checke;
                    else  state <= checkh;
                checke:
                    if(data == "e") state <= checkla;
                    else  state <= checkh;
                checkla:
                    if(data == "l") state <= checklb;
                    else  state <= checkh;
                checklb:
                    if(data == "l") state <= checko;
                    else  state <= checkh;
                checko:
                    if(data == "o")
                        begin
                        led <= ~led;
                        state <= checkh;
                        end
                    else  state <= checkh;
                default:state <= checkh;
            endcase
        end

endmodule

  1. 兩段式的編寫方式:
module  hello(
input clk,
input rst_n,
input [7:0] data,
output reg led
);


parameter checkh  = 5‘b0000_1,
             checke  = 5‘b0001_0,
             checkla = 5‘b0010_0,
             checklb = 5‘b0100_0,
             checko = 5‘b1000_0;

reg [4:0] cstate;
reg [4:0] nstate;

always @(posedge clk or negedge rst_n)
if(!rst_n)
        begin
            cstate <= checkh;
        end
else 
            cstate <= nstate;


always @(cstate or data)
            case (cstate)
                checkh:
                    if(data == "h") nstate <= checke;
                    else  nstate <= checkh;
                checke:
                    if(data == "e") nstate <= checkla;
                    else  nstate <= checkh;
                checkla:
                    if(data == "l") nstate <= checklb;
                    else  nstate <= checkh;
                checklb:
                    if(data == "l") nstate <= checko;
                    else  nstate <= checkh;
                checko:
                    if(data == "o")
                        begin
                        led <= ~led;
                        nstate <= checkh;
                        end
                    else  nstate <= checkh;
                default:nstate <= checkh;
            endcase

endmodule

  1. 三段式的編寫方式:
module  hello(
input clk,
input rst_n,
input [7:0] data,
output reg led
);


parameter checkh  = 5‘b0000_1,
             checke  = 5‘b0001_0,
             checkla = 5‘b0010_0,
             checklb = 5‘b0100_0,
             checko = 5‘b1000_0;

reg [4:0] cstate;
reg [4:0] nstate;

    //復位信號,clk的處理(主要是對初始狀態進行賦值操作)
always @(posedge clk or negedge rst_n)
if(!rst_n)
        begin
            cstate <= checkh;
        end
else 
            cstate <= nstate;

    //狀態遷移的處理
always @(cstate or data)
            case (cstate)
                checkh:
                    if(data == "h") nstate <= checke;
                    else  nstate <= checkh;
                checke:
                    if(data == "e") nstate <= checkla;
                    else  nstate <= checkh;
                checkla:
                    if(data == "l") nstate <= checklb;
                    else  nstate <= checkh;
                checklb:
                    if(data == "l") nstate <= checko;
                    else  nstate <= checkh;
                checko:
                    if(data == "o")
                        begin
                        nstate <= checkh;
                        end
                    else  nstate <= checkh;
                default:nstate <= checkh;
            endcase

    //輸出數據的處理
always @(posedge clk or negedge rst_n)
if(!rst_n)
        begin
            led <= 1‘b1;
        end
else 
        case (cstate)   
                checko:
                    if(data == "o")
                    led <= ~led;
                default;
            endcase

endmodule

註意

  1. 一般的狀態機是使用Always語句和case語句組合來實現的
  2. 不可以根據Always快的個數來判斷他是屬於幾段的狀態機
  3. 一般情況下不建議使用一段式狀態機,建議使用二和三段式狀態機,二段式狀態機使用時序邏輯處理狀態變化,組合邏輯處理輸入輸出的變化,結構比較清晰,但容易產生毛刺
  4. 三段式從輸入到輸出會比一、兩段式狀態機延時一個時鐘周期

fpga狀態機詳解