FPGA学习之状态机的多种描述方式(一段式,二段式,三段式)

​1.状态机的设计思路:

一是从状态变量入手,分析各个状态的输入,状态转移和输出

二是先确定电路的输出关系,再回溯规划每个状态的条件,输入等

2.状态机的三要素是状态,输入和输出,根据状态机状态是否和输入条件相关,可以分为摩尔型状态机(与输入条件相关)和米勒型状态机(与输入无关)

3.一段式描述:将用于状态转移判断的组合逻辑和用于状态寄存器转移的时序逻辑写在同一个always里面,在描述当前状态时还要考虑下一个状态的输出(这样写代码不清晰,难以维护)

二段式描述:输出使用的是组合逻辑,很容易产生毛刺等不稳定因素

三段式描述:根据对下一状态的判断,利用同步时序逻辑来寄存状态机的输出,从而消除了组合逻辑输出的不稳定性和毛刺的隐患,有利于时序路径分组

4.以自动售卖机为例:

一段式:

 

module auto_sell1(
    input clk,
    input rst_n,
    input half,         //0.5元
    input one,        //1元
    output reg drink,   //饮料售价2.5元,售出饮料信号
    output reg flag    //找零信号
);

reg [2:0] state;      //投币状态
parameter s0 = 3'b000;   //无投币
parameter s1 = 3'b001;   //投币0.5
parameter s2 = 3'b010;   //投币1
parameter s3 = 3'b011;   //投币1.5
parameter s4 = 3'b100;   //投币2
parameter s5 = 3'b101;   //投币2.5 拉高drink信号
parameter s6 = 3'b110;   //找零

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            drink <= 0;
            flag <= 0;
            state <= s0;
        end
    else
        begin
            case(state)
                s0: begin         //当为起始状态时,去判断有没有钱进来
                        if(half == 1'b1)    //当有0.5进时 则进入s1状态
                            state <= s1;
                        else if(one == 1'b1)//如果是直接进的1元,则进入s2状态
                            state <= s2;
                        else            //否则就是没有钱进入,停留在s0状态
                            state <= s0;
                    end 
                s1: begin                 //此时已经有0.5元了,判断是否有0.5进入,有的话进入s2状态
                        if(half == 1'b1)
                            state <= s2;
                        else if(one == 1'b1) //如果此时有投入1元 则进入s3
                            state <= s3;
                        else            //否则还是只有0.5 停在该状态
                            state <= s1;
                    end 
                s2: begin        //此时已经有1元
                        if(half == 1'b1)   //如果又投入0.5,进入s3
                            state <= s3;
                        else if(one == 1'b1)
                            state <= s4;
                        else
                            state <= s2;
                    end 
                s3: begin     //此时已经有1.5元
                        if(half == 1'b1)
                            state <= s4;
                        else if(one == 1'b1)
                            state <= s5;
                        else
                            state <= s3;
                    end 
                s4: begin         //此时已经有2元
                        if(half == 1'b1)
                            state <= s5;
                        else if(one == 1'b1)
                            state <= s6;
                        else
                            state <= s4;
                    end 
                s5: begin      //此时已经有2.5元
                        drink <= 1;
                        state <= s0;
                    end 
                s6: begin     //此时已经有3元
                        drink <= 1;
                        flag <= 1;
                        state <= s0;
                    end 
                default : state <= s0;
            endcase
        end
    
end

endmodule

 5.二段式:

 

module auto_sell2(
    input clk,
    input rst_n,
    input half,         //0.5元
    input one,        //1元
    output reg drink,   //饮料售价2.5元,售出饮料信号
    output reg flag    //找零信号
);

reg [2:0] c_state;      //投币状态
reg [2:0] n_state;
parameter s0 = 3'b000;   //无投币
parameter s1 = 3'b001;   //投币0.5
parameter s2 = 3'b010;   //投币1
parameter s3 = 3'b011;   //投币1.5
parameter s4 = 3'b100;   //投币2
parameter s5 = 3'b101;   //投币2.5 拉高drink信号
parameter s6 = 3'b110;   //找零
//第一段
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n) 
        c_state<= s0; 
    else
        c_state<= n_state;         
end
//第二段
always @(*)
begin
    if(!rst_n)
        begin
            drink <= 0;
            flag <= 0;
            n_state <= s0;
        end
    else
        begin
            case(c_state)
                s0: begin         //当为起始状态时,去判断有没有钱进来
                        if(half == 1'b1)    //当有0.5进时 则进入s1状态
                            n_state <= s1;
                        else if(one == 1'b1)//如果是直接进的1元,则进入s2状态
                            n_state <= s2;
                        else            //否则就是没有钱进入,停留在s0状态
                            n_state <= s0;
                    end 
                s1: begin                 //此时已经有0.5元了,判断是否有0.5进入,有的话进入s2状态
                        if(half == 1'b1)
                            n_state <= s2;
                        else if(one == 1'b1) //如果此时有投入1元 则进入s3
                            n_state <= s3;
                        else            //否则还是只有0.5 停在该状态
                            n_state <= s1;
                    end 
                s2: begin        //此时已经有1元
                        if(half == 1'b1)   //如果又投入0.5,进入s3
                            n_state <= s3;
                        else if(one == 1'b1)
                            n_state <= s4;
                        else
                            n_state <= s2;
                    end 
                s3: begin     //此时已经有1.5元
                        if(half == 1'b1)
                            n_state <= s4;
                        else if(one == 1'b1)
                            n_state <= s5;
                        else
                            n_state <= s3;
                    end 
                s4: begin         //此时已经有2元
                        if(half == 1'b1)
                            n_state <= s5;
                        else if(one == 1'b1)
                            n_state <= s6;
                        else
                            n_state <= s4;
                    end 
                s5: begin      //此时已经有2.5元
                        drink <= 1;
                        n_state <= s0;
                    end 
                s6: begin     //此时已经有3元
                        drink <= 1;
                        flag <= 1;
                        n_state <= s0;
                    end 
                default : n_state <= s0;
            endcase
        end
    
end

endmodule

 6.三段式:

 

 

 

module auto_sell3(
    input clk,
    input rst_n,
    input half,         //0.5元
    input one,        //1元
    output reg drink,   //饮料售价2.5元,售出饮料信号
    output reg flag    //找零信号
);

reg [2:0] c_state;      //投币状态
reg [2:0] n_state;
parameter s0 = 3'b000;   //无投币
parameter s1 = 3'b001;   //投币0.5
parameter s2 = 3'b010;   //投币1
parameter s3 = 3'b011;   //投币1.5
parameter s4 = 3'b100;   //投币2
parameter s5 = 3'b101;   //投币2.5 拉高drink信号
parameter s6 = 3'b110;   //找零
//第一段
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n) 
        c_state<= s0; 
    else
        c_state<= n_state;         
end
//第二段
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)      
        begin
            drink <= 0;
            flag <= 0;
        end
    else
        begin
            case(c_state)
                s0: begin         //当为起始状态时,去判断有没有钱进来
                        drink <= 0;
                        flag <= 0;
                    end 
                s1: begin                 //此时已经有0.5元了,判断是否有0.5进入,有的话进入s2状态
                        drink <= 0;
                        flag <= 0;
                    end 
                s2: begin        //此时已经有1元
                        drink <= 0;
                        flag <= 0;
                    end 
                s3: begin     //此时已经有1.5元
                        drink <= 0;
                        flag <= 0;
                    end 
                s4: begin         //此时已经有2元
                        drink <= 0;
                        flag <= 0;
                    end 
                s5: begin      //此时已经有2.5元 
                        drink <= 1;
                        flag <= 0;
                    end 
                s6: begin     //此时已经有3元                   
                       drink <= 1;
                       flag <= 1;
                    end 
                default : n_state <= s0;
            endcase
        end   
end

always @(*)
begin
    if(!rst_n)      
        n_state <= s0;
    else
        begin
            case(c_state)
                s0: begin         //当为起始状态时,去判断有没有钱进来
                        if(half == 1'b1)    //当有0.5进时 则进入s1状态
                            n_state <= s1;
                        else if(one == 1'b1)//如果是直接进的1元,则进入s2状态
                            n_state <= s2;
                        else            //否则就是没有钱进入,停留在s0状态
                            n_state <= s0;
                    end 
                s1: begin                 //此时已经有0.5元了,判断是否有0.5进入,有的话进入s2状态
                        if(half == 1'b1)
                            n_state <= s2;
                        else if(one == 1'b1) //如果此时有投入1元 则进入s3
                            n_state <= s3;
                        else            //否则还是只有0.5 停在该状态
                            n_state <= s1;
                    end 
                s2: begin        //此时已经有1元
                        if(half == 1'b1)   //如果又投入0.5,进入s3
                            n_state <= s3;
                        else if(one == 1'b1)
                            n_state <= s4;
                        else
                            n_state <= s2;
                    end 
                s3: begin     //此时已经有1.5元
                        if(half == 1'b1)
                            n_state <= s4;
                        else if(one == 1'b1)
                            n_state <= s5;
                        else
                            n_state <= s3;
                    end 
                s4: begin         //此时已经有2元
                        if(half == 1'b1)
                            n_state <= s5;
                        else if(one == 1'b1)
                            n_state <= s6;
                        else
                            n_state <= s4;
                    end 
                s5: begin      //此时已经有2.5元 
                        n_state <= s0;
                    end 
                s6: begin     //此时已经有3元                   
                        n_state <= s0;
                    end 
                default : n_state <= s0;
            endcase
        end   
end

endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值