FPGA系统性学习笔记连载_Day15【状态机、自动售货机】 【原理及verilog仿真】篇

2021-04-07 11:48:16 浏览数 (1)

FPGA系统性学习笔记连载_Day15【状态机、自动售货机】 【原理及verilog仿真】篇

本系列为FPGA系统性学习学员学习笔记整理分享,如有学习或者购买开发板意向,可加交流群联系群主。

连载《叁芯智能fpga设计与研发-第15天》 【状态机、自动售货机】 【原理及verilog仿真】

原创作者:紫枫术河 转载请联系群主授权,否则追究责任

本篇文章记录状态机的感念、及用状态机实现一个自动售货机的实验

一、状态机基本概念

状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调

相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类:

1.1、摩尔型,输出只与状态寄存器的输出状态有关

1.2、米粒型,输出不仅与状态寄存器的输出状态有关,还与组合逻辑的输入有关

1.3、状态机的状态个数必须是有限的

二、有限状态机

有限状态机是一种概念性机器,它能采取某种操作来响应一个外部事件。

1.1、具体采取的操作不仅能取决于接收到的事件;

1.2、还取决于各个事件的相对发生顺序。

之所以能做到这一点,是因为机器能跟踪一个内部状态,它会在收到事件后进行更新。

1.3、为一个事件而响应的行动不仅取决于事件本身,还取决于机器的内部状态。另外,采取的行动还会决定并更新机器的状态。

这样一来,任何逻辑都可建模成一系列事件/状态组合。

1.4 状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。

1.5、“现态”和“条件”是因,“动作”和“次态”是果。详解如下:

①现态:是指当前所处的状态。

②条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。

③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。

动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

④次态:条件满足后要前往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

三、自动售货机

自动售货机:假设一个售货机买一种饮料价格2.5元,投币只能是0.5元、1元,当累计投币>=2.5,售出饮料,并找零钱

1.1、根据我们投钱的组合,一共有5个状态,状态之间的转移如下图

1.2、状态之间的转移条件,如下表

1.3、verilog代码编写,这个例子我用的是一段式状态机

代码语言:javascript复制
module  auto_sell(
    input   clk,
    input       rst_n,
    input       coin_one,
    input       coin_half,
     
    output  reg     water,
    output  reg     coin_back
);
 
    parameter   ZERO        = 3'b000;
    parameter   HALF        = 3'b001;
    parameter   ONE         = 3'b010;
    parameter   ONE_HALF = 3'b011;
    parameter   TWO         = 3'b100;
     
    //一段式状态机
    reg [2:0]       status;
     
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            begin
                status   <= ZERO;
                water    <= 0;
                coin_back <= 0;
            end
        else
            case(status)
                ZERO :
                        begin  
                            water    <= 0;
                            coin_back <= 0;
                            if(coin_half)
                                status <= HALF;
                            else if(coin_one)
                                status <= ONE;
                            else
                                status <= status;
                        end
                HALF :
                        begin  
                            water    <= 0;
                            coin_back <= 0; 
                            if(coin_half)
                                status <= ONE;
                            else if(coin_one)
                                status <= ONE_HALF;
                            else
                                status <= status;   
                        end
                ONE :  
                        begin  
                            water    <= 0;
                            coin_back <= 0;
                            if(coin_half)
                                status <= ONE_HALF;
                            else if(coin_one)
                                status <= TWO;
                            else
                                status <= status;               
                        end
                ONE_HALF :
                            begin  
                                if(coin_half)
                                    begin
                                        status <= TWO;
                                        water    <= 1'b0;
                                        coin_back <= 1'b0;
                                    end
                                else if(coin_one)
                                    begin
                                        status <= ZERO;
                                        water    <= 1'b1;
                                        coin_back <= 1'b0;
                                    end
                                else
                                    begin
                                        status <= status;   
                                        water    <= 1'b0;
                                        coin_back <= 1'b0;                                      
                                    end
                            end
                TWO :  
                        begin  
                            if(coin_half)
                                    begin
                                        status <= ZERO;
                                        water    <= 1'b1;
                                        coin_back <= 1'b0;
                                    end
                            else if(coin_one)
                                    begin
                                        status <= ZERO;
                                        water    <= 1'b1;
                                        coin_back <= 1'b1;
                                    end
                            else
                                    begin
                                        status <= status;   
                                        water    <= 1'b0;
                                        coin_back <= 1'b0;                                      
                                    end    
                        end
                default:
                            begin
                                status <= ZERO; 
                                water    <= 1'b0;
                                coin_back <= 1'b0;                                      
                            end
            endcase        
    end
 
endmodule

1.4、仿真脚本

代码语言:javascript复制
module  auto_sell(
    input   clk,
    input       rst_n,
    input       coin_one,
    input       coin_half,
     
    output  reg     water,
    output  reg     coin_back
);
 
    parameter   ZERO        = 3'b000;
    parameter   HALF        = 3'b001;
    parameter   ONE         = 3'b010;
    parameter   ONE_HALF = 3'b011;
    parameter   TWO         = 3'b100;
     
    //一段式状态机
    reg [2:0]       status;
     
    always@(posedge clk,negedge rst_n)begin
        if(!rst_n)
            begin
                status   <= ZERO;
                water    <= 0;
                coin_back <= 0;
            end
        else
            case(status)
                ZERO :
                        begin  
                            water    <= 0;
                            coin_back <= 0;
                            if(coin_half)
                                status <= HALF;
                            else if(coin_one)
                                status <= ONE;
                            else
                                status <= status;
                        end
                HALF :
                        begin  
                            water    <= 0;
                            coin_back <= 0; 
                            if(coin_half)
                                status <= ONE;
                            else if(coin_one)
                                status <= ONE_HALF;
                            else
                                status <= status;   
                        end
                ONE :  
                        begin  
                            water    <= 0;
                            coin_back <= 0;
                            if(coin_half)
                                status <= ONE_HALF;
                            else if(coin_one)
                                status <= TWO;
                            else
                                status <= status;               
                        end
                ONE_HALF :
                            begin  
                                if(coin_half)
                                    begin
                                        status <= TWO;
                                        water    <= 1'b0;
                                        coin_back <= 1'b0;
                                    end
                                else if(coin_one)
                                    begin
                                        status <= ZERO;
                                        water    <= 1'b1;
                                        coin_back <= 1'b0;
                                    end
                                else
                                    begin
                                        status <= status;   
                                        water    <= 1'b0;
                                        coin_back <= 1'b0;                                      
                                    end
                            end
                TWO :  
                        begin  
                            if(coin_half)
                                    begin
                                        status <= ZERO;
                                        water    <= 1'b1;
                                        coin_back <= 1'b0;
                                    end
                            else if(coin_one)
                                    begin
                                        status <= ZERO;
                                        water    <= 1'b1;
                                        coin_back <= 1'b1;
                                    end
                            else
                                    begin
                                        status <= status;   
                                        water    <= 1'b0;
                                        coin_back <= 1'b0;                                      
                                    end    
                        end
                default:
                            begin
                                status <= ZERO; 
                                water    <= 1'b0;
                                coin_back <= 1'b0;                                      
                            end
            endcase        
    end
 
endmodule

1.5、仿真结果

从仿真结果,我们进行了2次投币,第一次投2.5元,出水,不找零;第二次投3元,出水并找零。

【QQ交流群】

群号:173560979,进群暗语:FPGA技术江湖粉丝。

多年的FPGA企业开发经验,各种通俗易懂的学习资料以及学习方法,浓厚的交流学习氛围,QQ群目前已有1000多名志同道合的小伙伴,无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有。

【微信交流群】

现微信交流群已建立09群,人数已达数千人,欢迎关注“FPGA技术江湖”微信公众号,可获取进群方式。

后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!

0 人点赞