【Verilog学习日常】—牛客网刷题—Verilog企业真题—VL61

自动售卖机

描述

请设计状态机电路,实现自动售卖机功能,A饮料5元钱,B饮料10元钱,售卖机可接收投币5元钱和10元钱,每次投币只可买一种饮料,考虑找零的情况。

电路的接口如下图所示。sel信号会先于din信号有效,且在购买一种饮料时不变。

  • sel为选择信号,用来选择购买饮料的种类,sel=0,表示购买A饮料,sel=1,表示购买B饮料;
  • din表示投币输入,din=0表示未投币,din=1表示投币5元,din=2表示投币10元,不会出现din=3的情况;
  • drinks_out表示饮料输出,drinks_out=0表示没有饮料输出,drinks_out=1表示输出A饮料,drinks_out=2表示输出B饮料,不出现drinks_out =3的情况,输出有效仅保持一个时钟周期
  • change_out表示找零输出,change_out=0表示没有找零,change_out=1表示找零5元,输出有效仅保持一个时钟周期。

接口电路图如下:

输入描述:

   input                clk   ,
   input                rst_n ,
   input                sel   ,//sel=0,5$dranks,sel=1,10&=$drinks
   input        [1:0] din   ,//din=1,input 5$,din=2,input 10$

输出描述:

   output   reg  [1:0] drinks_out,
   output   reg         change_out   

解题思路

有限状态机(FSM)相关知识:

  • 有限状态机是时序电路的通用模型,任何时序电路都可以表示为有限状态机;有限状态机从本质上讲是由寄存器与组合逻辑构成的时序电路,各个状态之间的转移总是在时钟的触发下进行的,状态信息存储在寄存器中。因为状态的个数是有限的所以称为有限状态机。
  • 同其他时序电路一样,有限状态机也是由两部分组成:存储电路组合逻辑电路。存储电路,用来生成状态机的状态;组合逻辑电路,用来提供输出以及状态机跳转的条件。

根据输出信号的产生方式,有限状态机可以分为米利型(Mealy)莫尔型(Moore)

  • Mealy型状态机的输出与当前状态和输入有关系;
  • Moore型状态机的输出仅依赖当前状态而与输入无关;

在Verilog HDL中,有限状态机的写法较多,常用的有两段式和三段式两种。下面给出三段式的一般格式;

//1.同步时序always模块,格式化描述次态寄存器迁移到现态寄存器
always @(posedge clk or negedge rst_n) //异步复位
if (!rst_n)    current_state <= IDLE;
else    current_state <= next_state; //注意,使用的是非阻塞赋值

//2.组合逻辑always模块,描述状态转移条件判断
always @(current_state) begin//电平触发
    begin
        next_state = x ; //要初始化,使得系统复位后能进入正确的状态
        case (current_state)
        S1: if(...)    
            next_state = S2; //阻塞赋值
        ...
        endcase
    end
end

//3.同步时序always1模块,格式化描述次态寄存器输出
always @(posedge clk or negedge rst_n) begin
    
    ...//初始化
    case(next_state)
    S1:
        out1 <= 1'b1 ; //非阻塞赋值
    S2:
        out2 <= 1'b1;
    default: ... //default的作用是免除综合工具综合出锁存器
    endcase
end

代码思路

根据售卖机中零钱数设置两个状态:

IDLE:售卖机里0元;

S1:售卖机中已投入5元;

对于找零(change_out)处理:当有饮料弹出的同时,才会退零钱,当没有饮料弹出时,即使售卖机中有钱,也会进入下一状态;

根据题目的要求,我们将一个完整的自动售卖机流程如下所示:

当售卖机里0元时:(即IDLE状态

sel = 1'b0, din=2'b00(购买A饮料,未投币)时,drinks_out = 2'b00, change_out = 1'b0;(IDLE)

sel = 1'b0, din=2'b01(购买A饮料,投币5元)时,drinks_out = 2'b01, change_out = 1'b0;(IDLE)

sel = 1'b0, din=2'b10(购买A饮料,投币10元)时,drinks_out = 2'b01, change_out = 1'b1;(IDLE)

sel = 1'b1, din=2'b00(购买B饮料,未投币)时,drinks_out = 2'b00, change_out = 1'b0;(IDLE)

sel = 1'b1, din=2'b01(购买B饮料,投币5元)时,drinks_out = 2'b00, change_out = 1'b0;(S1)

sel = 1'b1, din=2'b10(购买B饮料,投币10元)时,drinks_out = 2'b10, change_out = 1'b0;(IDLE)

当售卖机里已投入5元时:(即S1状态

sel = 1'b0, din=2'b00(购买A饮料,未投币)时,drinks_out = 2'b01, change_out = 1'b0; (IDLE)

sel = 1'b0, din=2'b01(购买A饮料,投币5元)时,drinks_out = 2'b01, change_out = 1'b1;(IDLE)

sel = 1'b0, din=2'b10(购买A饮料,投币10元)时,drinks_out = 2'b01, change_out = 1'b1;(S1)

sel = 1'b1, din=2'b00(购买B饮料,未投币)时,drinks_out = 2'b00, change_out = 1'b0;(S1)

sel = 1'b1, din=2'b01(购买B饮料,投币5元)时,drinks_out = 2'b00, change_out = 1'b0;(IDLE)

sel = 1'b1, din=2'b10(购买B饮料,投币10元)时,drinks_out = 2'b10, change_out = 1'b1;(IDLE)

`timescale 1ns/1ns

module sale(
   input                clk   ,
   input                rst_n ,
   input                sel   ,//sel=0,5$dranks,sel=1,10&=$drinks
   input          [1:0] din   ,//din=1,input 5$,din=2,input 10$
 
   output   reg  [1:0] drinks_out,//drinks_out=1,output 5$ drinks,drinks_out=2,output 10$ drinks
   output	reg        change_out   
);

parameter IDLE = 2'b01; //当前售卖机里0元
parameter S1 = 2'b10;   //当前售卖机已存5元


reg [1:0] current_state, next_state;
//1.
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) current_state <= IDLE;
    else    current_state <= next_state;
end
//2.条件转移判断
wire [2:0] data_in;
assign data_in[2:0] = {sel, din};

always @(*) begin
    case(current_state)
    IDLE: case (data_in) //当前售卖机里0元 
        3'b000: begin next_state<= IDLE;  end//购买A饮料, 投币0元
        3'b001: begin next_state<= IDLE;  end//购买A饮料, 投币5元
        3'b010: begin next_state<= IDLE;  end//购买A饮料, 投币10元
        3'b100: begin next_state<= IDLE;  end//购买B饮料, 投币0元
        3'b101: begin next_state<= S1;    end//购买B饮料, 投币5元   
        3'b110: begin next_state<= IDLE;  end//购买B饮料, 投币10元     
        endcase
    S1: case (data_in) 当前售卖机已存5元
        3'b000: begin next_state<= IDLE;   end//购买A饮料, 投币0元
        3'b001: begin next_state<= IDLE;   end//购买A饮料, 投币5元
        3'b001: begin next_state<= S1  ;   end//购买A饮料, 投币10元
        3'b100: begin next_state<= S1;     end//购买B饮料, 投币0元
        3'b101: begin next_state<= IDLE;   end//购买B饮料, 投币5元
        3'b110: begin next_state<= IDLE;   end//购买B饮料, 投币10元                            
        endcase
    default: next_state = IDLE;
    endcase
end
//3.给出输出
always @(posedge clk or negedge rst_n)  begin
    if(!rst_n) begin
        drinks_out = 2'b00;
        change_out = 1'b0;
    end
    else begin
        case (current_state) 
            IDLE: case (data_in) 
                3'b000: begin drinks_out = 2'b00; change_out = 1'b0; end
                3'b001: begin drinks_out = 2'b01; change_out = 1'b0; end 
                3'b010: begin drinks_out = 2'b01; change_out = 1'b1; end
                3'b100: begin drinks_out = 2'b00; change_out = 1'b0; end
                3'b101: begin drinks_out = 2'b00; change_out = 1'b0; end
                3'b110: begin drinks_out = 2'b10; change_out = 1'b0; end
                default: begin drinks_out = 2'b00; change_out = 1'b0; end 
            endcase
            S1: case (data_in)  //已有5元
                3'b000: begin drinks_out = 2'b01; change_out = 1'b0; end
                3'b001: begin drinks_out = 2'b01; change_out = 1'b1; end
                3'b010: begin drinks_out = 2'b01; change_out = 1'b1; end
                3'b100: begin drinks_out = 2'b00; change_out = 1'b0; end
                3'b101: begin drinks_out = 2'b10; change_out = 1'b0; end
                3'b110: begin drinks_out = 2'b10; change_out = 1'b1; end   
                default: begin drinks_out = 2'b00; change_out = 1'b0; end          
            endcase
            default: begin
                drinks_out = 2'b00; change_out = 1'b0;
            end      
        endcase
    end
end

endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值