FPGA系统性学习笔记连载_Day16【状态机:一段式、二段式、三段式】

2021-04-07 11:47:07 浏览数 (1)

FPGA系统性学习笔记连载_Day16【状态机:一段式、二段式、三段式】 【原理及verilog仿真】篇

本系列为FPGA系统性学习学员学习笔记整理分享,如有学习或者购买开发板意向,可加交流群联系群主。

连载《叁芯智能fpga设计与研发-第16天》 【状态机:一段式、二段式、三段式】 【原理及verilog仿真】

原创作者:紫枫术河 转载请联系群主授权,否则追究责任

本篇文章描述状态机的一段式、二段式、三段式区别

一、状态机

再次给出状态机的示意图:

1.1、摩尔型,输出只与状态寄存器的输出状态有关

1.2、米粒型,输出不仅与状态寄存器的输出状态有关,还与组合逻辑的输入有关

二、一段式、二段式、三段式区别

根据状态机的结构,状态机描述方式 可分为:一段式、二段式、三段式

1.1、一段式

整个状态机写到一个 always 模块里面。在该模块中既描述状态转移,又描述状态的输入和输出 。

1.2、二段式

用两个 always 模块来描述状态机。

1.2.1、其中一个 always 模块采用同步时序描述状态转移;

1.2.2、另一个 always模块采用组合逻辑判断状态转移条件,描述状态转移规律及其输出 ,注意组合逻辑输出要用阻塞赋值。

1.3、三段式

在两个 always 模块描述方法基础上,使用三个 always 模块。

1.3.1、 一个 always 模块采用同步时序描述状态转移;

1.3.2、一个 always 采用组合逻辑判断状态转移条件,描述状态转移规律,注意组合逻辑输出要用阻塞赋值;

1.3.3、另一个 always 模块描述状态输出(可以用组合电路输出,也可以时序电路输出),注意组合逻辑输出要用阻塞赋值。

1.4、综合

可以看出两段式有限状态机与一段式有限状态机的区别是将时序部分(状态转移)和组合部分(判断状态转移条件和产生输出)分开,写为两个 always语句,即为两段式有限状态机。将组合部分中的判断状态转移条件和产生输出再分开写,则为三段式有限状态机。

三、自动售货机、一段式

代码语言:javascript复制
module  auto_sell(
    input   clk,
    input       rst_n,
    input       coin_one,
    input       coin_half,
     
    output  reg     water,
    output  reg     coin_back
);
 
    parameter   ZERO        = 3'b000;
    parameter   HALF        = 3'b001;
    parameter   ONE         = 3'b010;
    parameter   ONE_HALF = 3'b011;
    parameter   TWO         = 3'b100;
     
    //一段式状态机
    reg [2:0]       status;
     
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            begin
                status   <= ZERO;
                water    <= 0;
                coin_back <= 0;
            end
        else
            case(status)
                ZERO :
                        begin  
                            water    <= 0;
                            coin_back <= 0;
                            if(coin_half)
                                status <= HALF;
                            else if(coin_one)
                                status <= ONE;
                            else
                                status <= status;
                        end
                HALF :
                        begin  
                            water    <= 0;
                            coin_back <= 0; 
                            if(coin_half)
                                status <= ONE;
                            else if(coin_one)
                                status <= ONE_HALF;
                            else
                                status <= status;   
                        end
                ONE :  
                        begin  
                            water    <= 0;
                            coin_back <= 0;
                            if(coin_half)
                                status <= ONE_HALF;
                            else if(coin_one)
                                status <= TWO;
                            else
                                status <= status;               
                        end
                ONE_HALF :
                            begin  
                                if(coin_half)
                                    begin
                                        status <= TWO;
                                        water    <= 1'b0;
                                        coin_back <= 1'b0;
                                    end
                                else if(coin_one)
                                    begin
                                        status <= ZERO;
                                        water    <= 1'b1;
                                        coin_back <= 1'b0;
                                    end
                                else
                                    begin
                                        status <= status;   
                                        water    <= 1'b0;
                                        coin_back <= 1'b0;                                      
                                    end
                            end
                TWO :  
                        begin  
                            if(coin_half)
                                    begin
                                        status <= ZERO;
                                        water    <= 1'b1;
                                        coin_back <= 1'b0;
                                    end
                            else if(coin_one)
                                    begin
                                        status <= ZERO;
                                        water    <= 1'b1;
                                        coin_back <= 1'b1;
                                    end
                            else
                                    begin
                                        status <= status;   
                                        water    <= 1'b0;
                                        coin_back <= 1'b0;                                      
                                    end    
                        end
                default:
                            begin
                                status <= ZERO; 
                                water    <= 1'b0;
                                coin_back <= 1'b0;                                      
                            end
            endcase        
    end
 
endmodule

四、自动售货机、二段式

1.1、二段式,写法一

代码语言:javascript复制
module  auto_sell(
    input   clk,
    input       rst_n,
    input       coin_one,
    input       coin_half,
     
    output  reg     water,
    output  reg     coin_back
);
 
    parameter   ZERO        = 3'b000;
    parameter   HALF        = 3'b001;
    parameter   ONE         = 3'b010;
    parameter   ONE_HALF = 3'b011;
    parameter   TWO         = 3'b100;
 
//--------------------二段式 1  ok--------------------------
    //二段式状态机
    reg [2:0]   c_status;
    reg [2:0]   n_status;
     
    //状态转移
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            c_status <= ZERO;
        else
            c_status <= n_status;
    end
     
    //描述状态转移规律以及输出
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            begin
                n_status <= ZERO;
                water <= 1'b0;
                coin_back <= 1'b0;  
            end
        else
            case(c_status)
                ZERO :
                        begin  
                            water <= 1'b0;
                            coin_back <= 1'b0;                          
                            if(coin_half)
                                n_status <= HALF;
                            else if(coin_one)
                                n_status <= ONE;
                            else
                                n_status <= ZERO;
                        end
                HALF :
                        begin  
                            water <= 1'b0;
                            coin_back <= 1'b0;                          
                            if(coin_half)
                                n_status <= ONE;
                            else if(coin_one)
                                n_status <= ONE_HALF;
                            else
                                n_status <= HALF;   
                        end
                ONE :  
                        begin  
                            water <= 1'b0;
                            coin_back <= 1'b0;                          
                            if(coin_half)
                                n_status <= ONE_HALF;
                            else if(coin_one)
                                n_status <= TWO;
                            else
                                n_status <= ONE;            
                        end
                ONE_HALF :
                            begin  
                                water <= 1'b0;
                                coin_back <= 1'b0;                              
                                if(coin_half)
                                        n_status <= TWO;
                                else if(coin_one)
                                    begin
                                        n_status <= ZERO;
                                        water <= 1'b1;
                                        coin_back <= 1'b0;  
                                    end
                                else
                                        n_status <= ONE_HALF;   
                            end
                TWO :  
                        begin  
                            water <= 1'b0;
                            coin_back <= 1'b0;                          
                            if(coin_half)
                                begin
                                    n_status <= ZERO;
                                    water <= 1'b1;
                                    coin_back <= 1'b0;                                      
                                end
                            else if(coin_one)
                                begin
                                    n_status <= ZERO;
                                    water <= 1'b1;
                                    coin_back <= 1'b1;                                          
                                end
                            else
                                n_status <= TWO;                                        
                        end
                default:
                            n_status <= ZERO;                                   
            endcase
    end
     
 
endmodule

1.2、二段式,写法二

代码语言:javascript复制
module  auto_sell(
    input   clk,
    input       rst_n,
    input       coin_one,
    input       coin_half,
     
    output  reg     water,
    output  reg     coin_back
);
 
    parameter   ZERO        = 3'b000;
    parameter   HALF        = 3'b001;
    parameter   ONE         = 3'b010;
    parameter   ONE_HALF = 3'b011;
    parameter   TWO         = 3'b100;
 
//---------------------二段式  2 ok--------------------------------------
 
    //二段式状态机
    reg [2:0]   status;
     
    //状态转移
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            status <= ZERO;
        else
            begin
                case(status)
                    ZERO :
                            begin                          
                                if(coin_half)
                                    status <= HALF;
                                else if(coin_one)
                                    status <= ONE;
                                else
                                    status <= ZERO;
                            end
                    HALF :
                            begin                          
                                if(coin_half)
                                    status <= ONE;
                                else if(coin_one)
                                    status <= ONE_HALF;
                                else
                                    status <= HALF; 
                            end
                    ONE :  
                            begin                      
                                if(coin_half)
                                    status <= ONE_HALF;
                                else if(coin_one)
                                    status <= TWO;
                                else
                                    status <= ONE;              
                            end
                    ONE_HALF :
                                begin                              
                                    if(coin_half)
                                            status <= TWO;
                                    else if(coin_one)
                                        begin
                                            status <= ZERO;
                                        end
                                    else
                                            status <= ONE_HALF; 
                                end
                    TWO :  
                            begin                          
                                if(coin_half)
                                    begin
                                        status <= ZERO;                                 
                                    end
                                else if(coin_one)
                                    begin
                                        status <= ZERO;                                     
                                    end
                                else
                                    status <= TWO;                                          
                            end
                    default:
                                status <= ZERO;                                 
                endcase        
            end
    end
 
 
    //输出 时序逻辑
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            begin
                water <= 1'b1;
                coin_back <= 1'b0;  
            end
        else
            case(status)
                ONE_HALF:
                            begin
                                if(coin_one)
                                    begin
                                        water <= 1'b1;
                                        coin_back <= 1'b0;
                                    end
                                else
                                    begin
                                        water <= 1'b0;
                                        coin_back <= 1'b0;                              
                                    end
                            end
                TWO:
                            begin
                                if(coin_half)
                                    begin
                                        water <= 1'b1;
                                        coin_back <= 1'b0;
                                    end
                                else if(coin_one)
                                    begin
                                        water <= 1'b1;
                                        coin_back <= 1'b1;                              
                                    end
                                else
                                    begin
                                        water <= 1'b0;
                                        coin_back <= 1'b0;                                  
                                    end
                            end
                default:
                            begin
                                water <= 1'b0;
                                coin_back <= 1'b0;                                  
                            end        
            endcase
    end
 
endmodule

五、自动售货机、三段式

代码语言:javascript复制
module  auto_sell(
    input   clk,
    input       rst_n,
    input       coin_one,
    input       coin_half,
     
    output  reg     water,
    output  reg     coin_back
);
 
    parameter   ZERO        = 3'b000;
    parameter   HALF        = 3'b001;
    parameter   ONE         = 3'b010;
    parameter   ONE_HALF = 3'b011;
    parameter   TWO         = 3'b100;
 
    //三段式状态机
    reg [2:0]   c_status;
    reg [2:0]   n_status;
     
    //状态转移
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            c_status <= ZERO;
        else
            c_status <= n_status;
    end
     
    //状态转移规律及状态输出,组合逻辑输出只与输入有关
    //如果有n_status = n_status,电路会出错;
    always@(*)begin
        case(c_status)
            ZERO :
                    begin  
                        if(coin_half)
                            n_status = HALF;
                        else if(coin_one)
                            n_status = ONE;
                        else
                            n_status = ZERO;
                    end
            HALF :
                    begin  
                        if(coin_half)
                            n_status = ONE;
                        else if(coin_one)
                            n_status = ONE_HALF;
                        else
                            n_status = HALF;   
                    end
            ONE :  
                    begin  
                        if(coin_half)
                            n_status = ONE_HALF;
                        else if(coin_one)
                            n_status = TWO;
                        else
                            n_status = ONE;            
                    end
            ONE_HALF :
                        begin  
                            if(coin_half)
                                n_status = TWO;
                            else if(coin_one)
                                n_status = ZERO;
                            else
                                n_status = ONE_HALF;                                       
                        end
            TWO :  
                    begin  
                        if(coin_half)
                            n_status = ZERO;
                        else if(coin_one)
                            n_status = ZERO;
                        else
                            n_status = TWO;        
                    end
            default:
                        n_status = ZERO;                                   
        endcase        
    end
 
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            begin
                water = 1'b1;
                coin_back = 1'b0;  
            end
        else
            case(c_status)
                ONE_HALF:
                            begin
                                if(coin_one)
                                    begin
                                        water = 1'b1;
                                        coin_back = 1'b0;
                                    end
                                else
                                    begin
                                        water = 1'b0;
                                        coin_back = 1'b0;                              
                                    end
                            end
                TWO:
                            begin
                                if(coin_half)
                                    begin
                                        water = 1'b1;
                                        coin_back = 1'b0;
                                    end
                                else if(coin_one)
                                    begin
                                        water = 1'b1;
                                        coin_back = 1'b1;                              
                                    end
                                else
                                    begin
                                        water = 1'b0;
                                        coin_back = 1'b0;                                  
                                    end
                            end
                default:
                            begin
                                water = 1'b0;
                                coin_back = 1'b0;                                  
                            end        
            endcase
    end
     
endmodule

六、仿真脚本

代码语言:javascript复制
`timescale 1ns/1ps
 
module auto_sell_tb;
 
    reg     clk;
    reg rst_n;
    reg coin_one;
    reg coin_half;
     
    wire    water;
    wire    coin_back;
     
     
     
    initial begin
        clk = 0;
        rst_n = 0;
        coin_one = 0;
        coin_half = 0;
        #20;
        rst_n = 1;
        //延时200us
        #10000
         
        //投2.5元
        coin_half = 1;
        #20;
        coin_half = 0;
        #20;
         
        coin_one = 1;
        #20;   
        coin_one = 0;  
        #20;
                 
        coin_half = 1;
        #20;
        coin_half = 0;
        #20;
                 
        coin_half = 1;
        #20;
        coin_half = 0; 
        #20;
                 
        //延时200us
        #10000
         
        //投3元
        coin_half = 1;
        #20;
        coin_half = 0;
        #20;
                 
        coin_one = 1;
        #20;   
        coin_one = 0;  
        #20;
                 
        coin_half = 1;
        #20;
        coin_half = 0;
        #20;
                 
        coin_one = 1;
        #20;   
        coin_one = 0;
        #20;
                 
        //延时200us
        #10000 
        $stop;
    end
     
    auto_sell auto_sell_inst(
        .clk            (clk),
        .rst_n      (rst_n),
        .coin_one   (coin_one),
        .coin_half  (coin_half),
     
        .water      (water),
        .coin_back  (coin_back)
    );
     
    always #10 clk = ~clk;
 
endmodule

七、仿真结果

【QQ交流群】

群号:173560979,进群暗语:FPGA技术江湖粉丝。

多年的FPGA企业开发经验,各种通俗易懂的学习资料以及学习方法,浓厚的交流学习氛围,QQ群目前已有1000多名志同道合的小伙伴,无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有。

【微信交流群】

现微信交流群已建立09群,人数已达数千人,欢迎关注“FPGA技术江湖”微信公众号,可获取进群方式。

后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!

0 人点赞