题解 | #自动贩售机2#

自动贩售机2

http://www.nowcoder.com/practice/298dec1c3dce45c881f3e53e02558828

解题思路

按照常规三段式,即可解题。

状态转移图

常规三段式,但值得注意的是,有两种饮料输出,相当于可以看成有两个状态机,所以画了两个状态转移图,分别是1.5元的和2,5元的,分别如下:

注:图中输入的钱用两位表示,高位表示1元,低位表示0.5元,一次只能投一个硬币;输出两位,高位表示出零钱0.5元,低位表示出饮料。

①对于饮料1,售价1.5元的:

alt

②对于饮料2,售价2.5元的: alt

代码细节

①和单饮料的售货机相比,只有第二段和第三段有差别,即多了一个sel选择信号来分支,所以相等于double了一下。

②中间段组合逻辑中没有输入硬币时,不能直接给原状态,而是赋予next_state来保持,我百度有说是因为在clk=0时,钱输入为0,此时处于default状态,要让next_state保持不变,而不是重置,也可能是输入只有半个周期的缘故,这里我不太懂,欢迎大家评论交流。

③这种有冗余状态的状态机,第3段需要用next_state而不是state。

代码实现

`timescale 1ns/1ns

module seller2(
	input wire clk  ,
	input wire rst  ,
	input wire d1   ,    //0.5元
	input wire d2   ,    //1元
	input wire sel  ,    //高电平选饮料2,2.5元的
	
	output reg out1 ,    //输出饮料1
	output reg out2 ,    //输出饮料2
	output reg out3      //输出0.5元零钱
);
    
    reg [6:0]   state, next_state;
    parameter   IDLE     =   7'b000_0001;
    parameter   HALF     =   7'b000_0010;
    parameter   ONE      =   7'b000_0101;
    parameter   ONE_HALF =   7'b000_1000;
    parameter   TWO      =   7'b001_0000;
    parameter   TWO_HALF =   7'b010_0000;
    parameter   THREE    =   7'b100_0000;

    always@(posedge clk or negedge rst) begin
        if(!rst)
            state <= IDLE;
        else
            state <= next_state;
    end

    always@(*) begin
        if(sel) begin   //饮料2,2.5元的
            case(state) //d1表示投入0.5元,d2表示投入1元
                IDLE    : next_state = d1 ? HALF     : (d2 ? ONE      : next_state );
                HALF    : next_state = d1 ? ONE      : (d2 ? ONE_HALF : next_state );
                ONE     : next_state = d1 ? ONE_HALF : (d2 ? TWO      : next_state );
                ONE_HALF: next_state = d1 ? TWO      : (d2 ? TWO_HALF : next_state );
                TWO     : next_state = d1 ? TWO_HALF : (d2 ? THREE    : next_state );
                TWO_HALF,
                THREE   : next_state = IDLE;
                default : next_state = IDLE;
            endcase
        end
        else begin
            case(state)
                IDLE    : next_state = d1 ? HALF     : (d2 ? ONE      : next_state );
                HALF    : next_state = d1 ? ONE      : (d2 ? ONE_HALF : next_state );
                ONE     : next_state = d1 ? ONE_HALF : (d2 ? TWO      : next_state );
                ONE_HALF,
                TWO     ,
                TWO_HALF,
                THREE   : next_state = IDLE;
                default : next_state = IDLE;
            endcase
        end
    end

    //注意:这种三段式输出要看next_state而不是state!
    always@(posedge clk or negedge rst) begin
        if(!rst) begin
            out1  <= 1'b0;
            out2  <= 1'b0;
            out3 <= 1'b0;
        end
        else if(sel) begin  //饮料2, 2.5元的
            out1  <= 1'b0;
            if(next_state == TWO_HALF) begin
                out2  <= 1'b1;
                out3 <= 1'b0;
            end
            else if(next_state == THREE) begin
                out2  <= 1'b1;
                out3 <= 1'b1;
            end
            else  begin
                out2  <= 1'b0;
                out3 <= 1'b0;
            end
        end
        else begin  //饮料1, 1.5元的
            out2  <= 1'b0;
            if(next_state == ONE_HALF) begin
                out1  <= 1'b1;
                out3 <= 1'b0;
            end
            else if(next_state == TWO) begin
                out1  <= 1'b1;
                out3 <= 1'b1;
            end
            else  begin
                out1  <= 1'b0;
                out3 <= 1'b0;
            end
        end
    end
    
endmodule
全部评论
我觉得是因为d的输入只有半个周期,而且是组合逻辑,假设前半个周期next_state是下个状态,在下半个周期变为0,nstate就变成原来状态了,相当于没投币,需要nstate=nstate保持住前半个周期的状态
2 回复 分享
发布于 2022-08-17 16:46 上海

相关推荐

2025-11-04 19:05
已编辑
东莞城市学院 单片机
不知道怎么取名字_:你这个要实习两年?哪有这么久的,感觉就是即使你毕业了,但还按实习的话,是不是不用给你缴社保公积金啥的
点赞 评论 收藏
分享
评论
7
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务