自动售货机的状态机实现

此文章用来记录笔者学习三段式状态机的一些思考

需求介绍:自动售货机可以投入1元、2元、5元的硬币,一次只能投入一种面额的硬币,获取商品价格为6元,当投入的金额大于6元时,会进行找零

状态划分

        最少的输入次数:5+1/2/5 >=6 2次

        最多的输入次数:1+1+1+!+!+! >= 6  6次

        输出找零情况:0/1/2/3/4   即输出找零位宽定为3位宽即可

因此状态可以定义为6个,加上上电初始状态和找零状态一共8个状态

状态转移草图

接口分析

输入信号

        i_sys_clk:系统工作时钟(50Mhz)

        i_sys_rst:复位信号,高电平有效

         i_one:投币1元的输入

        i_two:投币两元的输入

        i_five:投币五元的输入

输出信号

         o_thing:输出商品

        o_money:输出找零

代码编写

RTL代码

module  vm_fsm(
    input   wire            i_sys_clk       ,//时钟信号 
    input   wire            i_sys_rst       ,//复位信号
    input   wire            i_one           ,//1元
    input   wire            i_two           ,//2元
    input   wire            i_five          ,//5元

    output  reg             o_thing         ,//输出物品
    output  reg     [2:0]   o_money          //找零
    
);

/***************参数**************************/
parameter   MONEY_PAY = 'd6;

/***************状态机************************/
parameter   IDIE     =  8'b0000_0001, 
            IN1      =  8'b0000_0010, 
            IN2      =  8'b0000_0100,
            IN3      =  8'b0000_1000,
            IN4      =  8'b0001_0000,
            IN5      =  8'b0010_0000,
            IN6      =  8'b0100_0000,
            DONE     =  8'b1000_0000;
            
reg     [7:0]   r_cs_state  ;
reg     [7:0]   r_ns_state  ;

/***************寄存器************************/

/***************网表型************************/


/***************组合逻辑**********************/
reg     [3:0]   r_money_sum   ;

/***************时序逻辑**********************/

/
//时序逻辑,锁存状态
always@(posedge i_sys_clk)begin
    if(i_sys_rst == 1'b1)
        r_cs_state <= IDIE;
    else
        r_cs_state <= r_ns_state;
        
end

/
//组合逻辑,状态变迁
always@(*)begin
    case(r_cs_state)
        IDIE :if((i_one) || (i_two) || (i_five))
                    r_ns_state = IN1;
                else 
                    r_ns_state = IDIE;
        IN1 :if((i_one) || (i_two) || (i_five))
                    r_ns_state = IN2;
                else 
                    r_ns_state = IN1;  
        IN2 :  if(r_money_sum >= MONEY_PAY)
                    r_ns_state = DONE;
                else if((i_one) || (i_two) || (i_five))
                    r_ns_state = IN3;
                else 
                    r_ns_state = IN2;
        IN3 :if(r_money_sum >= MONEY_PAY)
                    r_ns_state = DONE;
                else if((i_one) || (i_two) || (i_five))
                    r_ns_state = IN4;
                else 
                    r_ns_state = IN3;
        IN4 :if(r_money_sum >= MONEY_PAY)
                    r_ns_state = DONE;
                else if((i_one) || (i_two) || (i_five))
                    r_ns_state = IN5;
                else 
                    r_ns_state = IN4;
        IN5 :if(r_money_sum >= MONEY_PAY)
                    r_ns_state = DONE;
                else if((i_one) || (i_two) || (i_five))
                    r_ns_state = IN6;
                else 
                    r_ns_state = IN5;
        IN6 :if(r_money_sum >= MONEY_PAY)
                    r_ns_state = DONE;
                else if((i_one) || (i_two) || (i_five))
                    r_ns_state = DONE;
                else 
                    r_ns_state = IN6;
        DONE :r_ns_state = IDIE;
        default:r_ns_state = IDIE;
    endcase
    
end

/
//r_money_sum
always@(posedge i_sys_clk)begin
    if(i_sys_rst == 1'b1)
        r_money_sum <= 'd0;
    else begin
        case(r_cs_state)
            DONE:r_money_sum <= 'd0;
            default:begin 
                if(i_one)
                    r_money_sum <= r_money_sum + 1'b1;
                else if(i_two)
                    r_money_sum <= r_money_sum + 'd2;
                else if(i_five)
                    r_money_sum <= r_money_sum + 'd5;
                else 
                    r_money_sum <= r_money_sum;
            end
        endcase
    end
  
end

/
//o_thing
always@(posedge i_sys_clk)begin
    if(r_cs_state == DONE)
        o_thing <= 1'b1;
    else 
        o_thing <= 1'b0;

end 

/
//o_money
always@(posedge i_sys_clk)begin
    if(r_cs_state == DONE)
        o_money <= r_money_sum - MONEY_PAY;
    else 
        o_money <= 'd0;

end 
endmodule


仿真测试代码

`timescale 1ns/1ns 

module  tb_vlg_design();
reg                i_sys_clk   ;//时钟信号
reg                i_sys_rst   ;//复位信号
reg                i_one       ;//1元
reg                i_two       ;//2元
reg                i_five      ;//5元
reg     [31:0]     state       ;//用来观察状态机的变量

wire               o_thing     ;//输出物品
wire    [2:0]      o_money     ;


//产生时钟和复位
initial
    begin
        i_sys_clk = 1'b1;
        i_sys_rst <= 1'b1;
        #100
        i_sys_rst <= 1'b0;
    end

always #10 i_sys_clk =  ~i_sys_clk;


//产生投入硬币输入激励
integer i;
initial
    begin
        i_one <= 1'b0;
        i_two <= 1'b0;
        i_five <= 1'b0;
        @(negedge i_sys_rst);//等待复位完成
       
       //调用50次任务
        @(posedge i_sys_clk);
            for(i=0;i<50;i=i+1)begin
                input_money();
            end
    
    end
    

//简化输入激励产生
//并且每次只有一种硬币投入
integer random_data;    
task input_money();
begin
    random_data <= {$random} % 3;
    @(posedge i_sys_clk);
        begin
            if(random_data == 'd0)
                i_one <= 1'b1;
            else if(random_data == 'd1)
                i_two <= 1'b1;
            else if(random_data == 'd2)
                i_five <= 1'b1;
            else ;
        end
    @(posedge i_sys_clk);
        begin
            i_one <= 1'b0;
            i_two <= 1'b0;
            i_five <= 1'b0;
        end
end
endtask


//状态机观察
always@(*)
    begin
        case(vm_fsm_inst.r_cs_state)
            8'b0000_0001 :state = "IDIE" ;
            8'b0000_0010 :state = "IN1"  ;
            8'b0000_0100 :state = "IN2"  ;
            8'b0000_1000 :state = "IN3"  ;
            8'b0001_0000 :state = "IN4"  ;
            8'b0010_0000 :state = "IN5"  ;
            8'b0100_0000 :state = "IN6"  ;
            8'b1000_0000 :state = "DONE" ;
            default:state = "IDIE" ;
        endcase
    end


//例化
vm_fsm vm_fsm_inst
(
    . i_sys_clk   (i_sys_clk ),//时钟信号 
    . i_sys_rst   (i_sys_rst ),//复位信号
    . i_one       (i_one     ),//1元
    . i_two       (i_two     ),//2元
    . i_five      (i_five    ),//5元
                   
    . o_thing     (o_thing   ),//输出物品
    . o_money     (o_money   ) //输出找零
    
);


endmodule

 仿真分析

利用modelsim单独仿真,让仿真运行了 2us,此时可以看到输入了一个1元的硬币和5元的硬币,状态跳转到DONE,并且输出物品信号拉高,没有进行找零,内部已投硬币计数r_money_sum清零,符合设计的要求
此时可以看到输入了一个1元的硬币、2元的硬币和5元的硬币,状态跳转到DONE,并且输出物品信号拉高,找零两元,此时的找零信号清零,符合设计的要求

总结

1、FPGA具有并行处理的特性,固使用RTL代码设计的电路都具有并行性。

        在实际的电路中,当需要处理“前后顺序的事件时”,就有了状态机的引入

2、绘制状态转移图的三要素

        1)输入:决定状态机的状态跳转和输出,(当输入不足以使状态机进行跳转时,可以使用内部的变量来辅助状态机的跳转,这也是工程中最常用的方式)

        2)输出:根据"当前时刻的输入和状态“决定,是状态机设计的主要目的

        3)状态:根据输入和上一状态决定当前时刻所处的状态,是状态机系统执行的一个稳定的过程

3、状态机的重点   

     如何将实际问题抽象成对应的状态,是需要不断去练习才能掌握的,也是状态机的精髓。状态是控制流程中的节点,问题的复杂度决定了状态的多少。状态间具有互斥性,在同一时刻,状态机仅可能具有一个状态。

        在实际的应用中,不用去刻意区分moore型状态机还是mealy型状态机,使用状态机的目的就是需要利用能处理“前后顺序的事件”的特点来解决实际问题

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Verilog自动售货机实现是通过使用Verilog语言来描述售货机的行为和逻辑,包括输入输出、控制信号、状态转换等。通过Verilog语言的描述,可以将自动售货机的功能实现FPGA或ASIC中,从而实现一个完全由硬件来实现自动售货机。这个自动售货机可以根据用户的选择,自动出售商品并扣除相应的费用,同时可以显示交易信息和状态。 ### 回答2: Verilog 是一种硬件描述语言,能够描述数字电路的行为和结构。自动售货机状态机的经典示例,因此我们可以使用 Verilog 描述自动售货机状态机。下面是详细的步骤: 1. 指定状态:自动售货机的状态图是由多个状态组成的,每个状态代表售货机不同的状态。例如,我们可以定义以下状态:待机、接收货币、选择商品、出货、退货等等。 2. 定义输入输出信号:这些信号将被用来控制状态机的行为。输入信号可能包括按钮、货币接口和显示屏等。输出信号可能包括灯、电机和音频信号等。我们需要定义每个输入和输出信号及其对应的作用。 3. 指定状态转移条件和动作:状态转移指定了状态机从一个状态转移到另一个状态所需的条件,例如,如果货币输入正确,自动售货机应转移到选择商品的状态。动作指定了状态机在转移时必须执行的操作,例如,在出货状态下,我们需要执行出货动作,将商品投放到出货口。 4. 编写 Verilog 代码实现状态机:根据上述步骤,我们可以编写 Verilog 代码实现状态机。我们将输入、输出信号、状态和状态转移和动作分别作为模块输入、输出、参数和逻辑实现的条件,然后设置逻辑实现,使状态机根据输入信号转移到不同的状态,并执行相应的操作输出信号。 综上所述,Verilog 自动售货机状态机实现的过程需要明确状态、输入输出信号以及状态转移条件和动作,并编写相应逻辑实现。根据这些步骤,我们可以通过 Verilog 描述状态机,控制自动售货机的行为。 ### 回答3: Verilog 是一种硬件描述语言,用于电子系统级别的设计和验证。它有丰富的库和模块,使得我们可以对各种电子器件进行建模,并且能够在较高的抽象层次上进行设计、优化和验证。 自动售货机是一个常见的应用场景,我们可以用 Verilog 来实现状态机。首先,我们需要定义自动售货机的各个状态,该状态机有以下状态: 1. 初始状态 2. 等待投币状态 3. 投币状态 4. 等待选择状态 5. 选择状态 6. 支付状态 7. 出货状态 在初始状态下,我们需要初始化自动售货机中的各个计数器,并等待着用户投币,这时候状态机会进入等待投币状态。在等待投币状态下,自动售货机会等待着用户投入硬币,如果用户投硬币,它会进入投币状态。在投币状态下,自动售货机会将投币的钱数加起来,并等待用户选择商品状态机会转移到等待选择状态。在等待选择状态下,自动售货机会等待用户输入商品编号,如果输入正确,状态机会进入选择状态。在选择状态下,自动售货机会进行支付,如果用户付款成功,状态机会进入支付状态。在支付状态下,自动售货机会进行出货,如果成功出货,状态机会进入出货状态。在出货状态下,自动售货机会等待用户将商品取走,完成交易。 以上是自动售货机状态机实现思路,我们需要根据实际情况进行具体的实现。通过使用 Verilog 和状态机,我们可以很方便地设计各种硬件系统,从而能够更加高效地进行电子系统的设计、仿真和验证。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值