verilog 售卖机 三段式状态机

状态机类型

Moore 状态机

Moore 型状态机的输出只与当前状态有关,与当前输入无关。输入对输出的影响要到下一个时钟周期才能反映出来。

Mealy 状态机。

Mealy 型状态机的输出,不仅与当前状态有关,还取决于当前的输入信号。输入变化可能出现在任何状态的时钟周期内


Mealy型3段式状态机 自动售卖机:

状态转移图:
在这里插入图片描述
自动售卖机的功能描述如下:

饮料单价 2 元,该售卖机只能接受 0.5 元、1 元的硬币。考虑找零和出货。投币和出货过程都是一次一次的进行,不会出现一次性投入多币或一次性出货多瓶饮料的现象。每一轮售卖机接受投币、出货、找零完成后,才能进入到新的自动售卖状态。

其中,coin = 1 代表投入了 0.5 元硬币,coin = 2 代表投入了 1 元硬币。

// 售卖机  三段式状态机

module  vending_machine_p3  (
    input           clk,   
    input           rstn,   
    input   [1:0]   coin,    // 投入硬币  01 for 0.5 jiao, 10 for 1 yuan
    output  [1:0]   change,  // 找零
    output          sell     // 出货
    );

    // 状态码
    parameter   IDLE    =   3'd0;
    parameter   GET05   =   3'd1;  // 收了5毛
    parameter   GET10   =   3'd2;  // 收了1元
    parameter   GET15   =   3'd3;  // 收了1.5元

    reg [2:0]   next_state;
    reg [2:0]   current_state;

    // 状态机第一段,时序逻辑,非阻塞赋值,传递寄存器的状态
    always @(posedge clk or negedge rstn) begin
        if(~rstn) begin
            next_state <= 3'b0;
            current_state <= 3'b0;
        end 
        else begin
            current_state <= next_state;
        end
    end

    // 状态机第二段,组合逻辑,阻塞赋值,根据当前状态和当前输入,确定下一个状态机的状态。
    always @(*) begin
        case(current_state)
            IDLE:
                case(coin)
                    2'b01:  next_state = GET05; // 收了5毛
                    2'b10:  next_state = GET10; // 收了1元
                    default:next_state = IDLE;  // 原地不动
                endcase 
            GET05:
                case(coin)
                    2'b01:  next_state = GET10; // 收了1元
                    2'b10:  next_state = GET15; // 收了1.5元
                    default:next_state = GET05; // 原地不动
                endcase 
            GET10:
                case(coin)
                    2'b01:  next_state = GET15; // 收了1.5元
                    2'b10:  next_state = IDLE;  // 收了2元,达到单价,返回
                    default:next_state = GET10; // 原地不动
                endcase 
            GET15:
                case(coin)
                    2'b01:  next_state = IDLE; // 收了2元,达到单价,返回
                    2'b10:  next_state = IDLE; // 收了2.5元,超过单价,找零,返回
                    default:next_state = GET15; // 原地不动
                endcase 
            default:
                next_state = IDLE;                                                                  
        endcase // current_state
    end

    // 状态机第三段,时序逻辑,非阻塞赋值,因为是 Mealy 型状态机,根据当前状态和当前输入,确定输出信号
    reg [1:0]   change_r;
    reg         sell_r;
    always @(posedge clk or negedge rstn) begin 
        if(~rstn) begin
            change_r <= 2'b0 ;
            sell_r <= 1'b0;
        end 
        else if ((current_state == GET15 && coin == 2'd1 ) 
                    || (current_state == GET10 && coin == 2'd2 ))begin
            change_r <=  2'b0 ;
            sell_r <= 1'b1;  // 出货
        end
        else if (current_state == GET15 && coin == 2'd2 )begin
            change_r <=  2'b1 ;  // 找零
            sell_r <= 1'b1;    // 出货
        end
        else begin  // default
            change_r <= 2'b0 ;
            sell_r <= 1'b0;         
        end
    end

    assign sell = sell_r;
    assign change  = change_r;

endmodule

`timescale 1ns/1ps

module vending_machine_p3_tb ;
    reg             clk;  
    reg             rstn;    
    reg     [1:0]   coin;     // 投入硬币  01 for 0.5 jiao, 10 for 1 yuan
    wire    [1:0]   change;   // 找零
    wire            sell;      // 出货

   //(1) mealy state with 3-stage
    vending_machine_p3    u_mealy_p3     (
        .clk(clk),
        .rstn(rstn),
        .coin(coin),
        .change(change),
        .sell(sell)
        );

    // 仿真停止
    always begin
      #100;
      if ($time >= 10000)  $finish ;
    end


    parameter CYCLE_200MHz = 10;  // 1/200*10^6 = 5*10^-9 = 5ns 半周期
    always begin
        clk = 0 ; #(CYCLE_200MHz/2) ;  // 半周期翻转#(CYCLE_200MHz/2)
        clk = 1 ; #(CYCLE_200MHz/2) ;
    end

    reg [9:0]   buy_oper;  // 操作状态
    initial begin
        buy_oper    =   10'd0;
        coin        =   2'd0;   
        rstn        =   1'd0;
        #8 rstn     =   1'b1;  // (即仿真开始后的第8ns,第一个周期内)(一个周期10ns)

        @(negedge clk);  // 从下降沿开始(即仿真开始后的第10ns)

        //case(1) 0.5 -> 0.5 -> 0.5 -> 0.5
        #16;    // 等待16ns  (即仿真开始后的第26ns,第3个周期内)
        buy_oper  = 10'b00_0101_0101 ;
        repeat(5) begin
            @(negedge clk);   // 再过4ns到下降沿 (即仿真开始后的第30ns)
            coin        =   buy_oper[1:0];
            buy_oper    =   buy_oper >> 2;  // 右移两位 (每次都给5毛)
        end

        //case(2)  1 -> 0.5 -> 1
        #16;  // 再过16ns (即仿真开始后的第46ns,clk=1在45ns-50ns之间)
        buy_oper  = 10'b00_0010_0110 ;
        repeat(5) begin
            @(negedge clk);  // 再过4ns到下降沿 (即仿真开始后的第50ns)
            coin        =   buy_oper[1:0];
            buy_oper    =   buy_oper >> 2;  // 右移两位 (每次都给5毛)
        end

        //case(3) 0.5 -> 1 -> 0.5
        #16 ;
        buy_oper  = 10'b00_0001_1001 ;
        repeat(5) begin
            @(negedge clk) ;
            coin      = buy_oper[1:0] ;
            buy_oper  = buy_oper >> 2 ;
        end

        //case(4) 0.5 -> 0.5 -> 0.5 -> 1
        #16 ;
        buy_oper  = 10'b00_1001_0101 ;
        repeat(5) begin
            @(negedge clk) ;
            coin      = buy_oper[1:0] ;
            buy_oper  = buy_oper >> 2 ;
        end        
    end


endmodule // test

在这里插入图片描述


  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值