FPGA学习_状态机:使用vivado写一个简单的状态机程序,模拟自动售货机售卖可乐

一、状态机简介

FPGA中的状态机是一种基于状态转移的设计方法,它可以实现复杂的控制逻辑和状态管理。状态机通常由状态寄存器、状态转移逻辑和输出逻辑组成。

状态寄存器用于存储当前状态,状态转移逻辑用于根据输入信号和当前状态计算下一个状态,输出逻辑用于根据当前状态和输入信号计算输出信号。状态机可以实现多种功能,例如序列检测、计数器、状态控制等。

在FPGA中,状态机可以使用Verilog或VHDL等硬件描述语言进行设计和实现。我们需要定义状态寄存器、状态转移逻辑和输出逻辑,并将其综合到FPGA中。状态机的设计需要考虑时序约束、时钟域等因素,以确保正确性和可靠性。

二、分类

状态机可以根据不同的特征进行分类,常见的分类方式包括以下几种:

  1. Moore状态机和Mealy状态机:Moore状态机的输出只与当前状态有关,而Mealy状态机的输出不仅与当前状态有关,还与输入信号有关。

  2. 同步状态机和异步状态机:同步状态机的状态转移和输出逻辑都与时钟信号同步,而异步状态机的状态转移和输出逻辑不与时钟信号同步。

  3. 有限状态自动机和无限状态自动机:主要是指状态数是否是有限的。

  4. 顺序状态机和组合状态机:顺序状态机的输出不仅与当前输入有关,还与之前的输入有关,而组合状态机的输出只与当前输入有关。

  5. 硬件状态机和软件状态机:硬件状态机是在FPGA中实现的,而软件状态机是在软件中实现的。硬件状态机具有高效、低功耗、可重构等优点,而软件状态机具有灵活、易于修改等优点。

三、售货机实验

主要实现功能:除时钟和复位外,定义两种输入——0.5元和1元硬币;售卖机有5种状态——空闲、已投入0.5元到2元4种状态;定义两种输出——找零0.5元和出可乐。

四、代码

选用两段式,一段为时序逻辑描述转移,一段为组合逻辑描述输出。在进行综合时,系统会自动将这种代码识别为状态机。

`timescale 1ns / 1ps  //设置时间单位


module cola_fsm2(
input  wire clk,
input  wire rst_n,
input  wire pi_money_one,
input  wire pi_money_half,
output wire po_cola,
output wire po_money
    );
//定义参数类型
    reg [2:0] state;
    reg po_cola_p, po_money_p;
    wire  [1:0] pi_money;

//设置状态参数    
    parameter
    idle=3'b000,half=3'b001,one=3'b010,onehalf=3'b011,
    two=3'b100;

//使用拼接符赋值
assign pi_money = {pi_money_one,pi_money_half};

//时序逻辑描述转移
always @(posedge clk or negedge rst_n)
    if(rst_n == 1'b0)
    state <= idle;
    else
    case(state)
    idle : if(pi_money == 2'b01)
           state <= half;
           else if(pi_money == 2'b10)
           state <= one;
           else
           state <= idle;
    half : if(pi_money == 2'b01)
           state <= one;
           else if(pi_money== 2'b10)
           state <= onehalf;
           else
           state <= half;
    one  : if(pi_money == 2'b01)
           state <= onehalf;
           else if(pi_money== 2'b10)
           state <= two;
           else
           state <= one; 
    onehalf:if(pi_money == 2'b01)
           state <= two;
           else if(pi_money == 2'b10)
           state <= idle;
           else
           state <= onehalf;
    two  : if(pi_money == 2'b01)
           state <= idle;
           else if(pi_money== 2'b10)
           state <= idle;
           else
           state <= two;
     default: state <= idle;       
    endcase

//组合逻辑描述输出
always @ (posedge clk or negedge rst_n)
     if (rst_n == 1'b0)
       state <= idle;
     else if (((state == two) && (pi_money == 2'b01)) || ((state==onehalf) && (pi_money==2'b10)))
//使用并行块非阻塞赋值
       fork
       po_cola_p <= 1'b1;
       po_money_p <= 1'b0;
       join
     else if ((state == two )&& (pi_money == 2'b10))
       fork
       po_cola_p <= 1'b1;
       po_money_p <= 1'b1;
       join
     else
       fork
       po_cola_p <= 1'b0;
       po_money_p <= 1'b0;
       join

//将寄存器值分配给输出
assign po_cola=po_cola_p;
assign po_money=po_money_p;

endmodule

五、编写仿真文件

`timescale 1ns / 1ps

module cola_fsm2_tb(
    );
reg clk,rst_n,pi_money_one,pi_money_half;
reg random;
wire po_money,po_cola;

always  #20 clk = ~clk;  //产生一个以40ns为周期的时钟

//在前半个时钟使复位键处于高电平
initial
   begin
   rst_n <= 1'b0;
   clk <= 1'b1;
   #20
   rst_n <= 1'b1;
   end

//将投币面值设置为随机数,
always @(posedge clk or negedge rst_n)
    if(rst_n == 1'b0)
    random=0;
    else
    random <= {$random}%2;

always @(posedge clk or negedge rst_n)
    if(rst_n == 1'b0)
     fork
     pi_money_half <= 1'b0;
     pi_money_one <= 1'b0;
     join
    else
     fork
     pi_money_one <= random;
     pi_money_half <= ~random;
     join

//将状态和输入硬币与引用模块的成员连接
 wire [2:0] state=cola_fsm2_tb.state;
 wire [1:0] pi_money=cola_fsm2_tb.pi_money; 

initial
   begin
   $timeformat(-9,0,"ns",6);//设置仿真时间格式,-9表示时间单位为ns、精度为1ns

//监视信号的值并在控制台上显示,监视的信号有变化时自动更新
$monitor("time=%t,state=%b,random=%b,po_money=%b,po_cola=%b",$time,state,random,po_money,po_cola);
   end

//引用源模块 
cola_fsm2 cola_fsm2_tb(
.clk(clk),
.rst_n(rst_n),
.pi_money_one(pi_money_one),
.pi_money_half(pi_money_half),
.po_cola(po_cola),
.po_money(po_money)
    );
 
endmodule

六、仿真结果分析

 观察仿真结果可知:在第2、3个时钟周期分别投入了0.5元,第4、5个时钟周期分别投入了1元,共计3元,此时state值为4(two状态),因为是非阻塞赋值,所以在下一个时钟周期才会吐出可乐和找零0.5元,同时state跳转为0(idle状态)。

声明:此实验为野火FPGA状态机教程之二,基本架构相同,代码有所修改,欢迎交流讨论。

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值