【FPGA】Verilog语言通过状态机实现可乐机系统

一、实验概述

上一篇博客实现了1元硬币的可乐机系统,
参考链接: 【FPGA】状态机的理论学习与实战演练(1元硬币可乐机系统)

此处提升难度,投入硬币的面值除了1元,还可投入0.5元,将可乐的售价定位2.5元。
投币如果不足2.5元,不吐出可乐。
投币如果超过2.5元,吐出可乐并找零钱。

二、模块框图

在这里插入图片描述
包含四个输入信号:系统时钟(sys_clk)、复位信号(sys_rst_n)、投币0.5元信号(pi_money_half)以及投币1元信号(pi_money_one)。
两个输出信号:输出可乐(po_cola)、找零(po_money)。

三、状态转移图

在这里插入图片描述
在这里插入图片描述

四、波形图

1、时钟与复位信号

在这里插入图片描述

2、投币信号

(随机画出)
在这里插入图片描述

3、投币记录信号

组合逻辑
在这里插入图片描述

4、状态变量信号

在这里插入图片描述

5、输出信号

在这里插入图片描述

五、代码部分

1、Verilog代码

module complex_fsm
(
  input wire sys_clk,
  input wire sys_rst_n,
  input wire pi_money_half,
  input wire pi_money_one,
  
  output reg po_cola,
  output reg po_money
);

parameter IDLE     = 5'b00001,
          HALF     = 5'b00010,
          ONE      = 5'b00100,
          ONE_HALF = 5'b01000,
          TWO      = 5'b10000;

wire [1:0] pi_money;
reg  [4:0] state;

assign pi_money = {pi_money_one,pi_money_half};

always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_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 <= ONE_HALF;
					else
					  state <= HALF;
			ONE: if(pi_money == 2'b01)
			        state <= ONE_HALF;
				  else if(pi_money == 2'b10)
				     state <= TWO;
				  else
				     state <= ONE;
			ONE_HALF:if(pi_money == 2'b01)
			        state <= TWO;
			      else if(pi_money == 2'b10)
					  state <= IDLE;
					else
					  state <= ONE_HALF;
			 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 sys_clk or negedge sys_rst_n)
       if(sys_rst_n == 1'b0)
		    po_cola <= 1'b0;
		 else if((state == ONE_HALF && pi_money == 2'b10)
		      || (state == TWO && pi_money == 2'b01)
				|| (state == TWO && pi_money == 2'b10))
		    po_cola <= 1'b1;
		 else
		    po_cola <= 1'b0;
			 
always@(posedge sys_clk or negedge sys_rst_n)
       if(sys_rst_n == 1'b0)
		    po_money <= 1'b0;
		 else if((state == TWO)&&(pi_money == 2'b10))
		    po_money <= 1'b1;
		 else
		    po_money <= 1'b0;
			 
endmodule
				  

2、tb仿真代码

因投币机同一时间只能投一枚硬币,故pi_money_half与pi_money_one不可能同时为高电平
因此仿真时引入random_date,令pi_money_half = random_date,
pi_money_one = ~random_date

`timescale 1ns/1ns
module tb_complex_fsm();
reg sys_clk;
reg sys_rst_n;
reg pi_money_half;
reg pi_money_one;
reg random_date;

wire po_cola;
wire po_money;

initial
   begin
	   sys_clk = 1'b1;
		sys_rst_n <= 1'b0;
		#20
		sys_rst_n <= 1'b1;
	end
	
always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0)
		  random_date <= 1'b0;
		else
		  random_date <= {$random} % 2;
		  
always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0)
		  pi_money_half <= 1'b0;
		else
		  pi_money_half <= random_date;
		  
always@(posedge sys_clk or negedge sys_rst_n)
      if(sys_rst_n == 1'b0)
		  pi_money_one <= 1'b0;
		else
		  pi_money_one <= ~random_date;
	
always #10 sys_clk = ~sys_clk;

wire [1:0] pi_money = complex_fsm_inst.pi_money;
wire [4:0] state = complex_fsm_inst.state;

initial
     begin
	     $timeformat(-9,0,"ns",6);
		  $monitor("@time %t:pi_money_half=%b,pi_money_one=%b,pi_money=%b,state=%b,po_cola=%b,po_money=%b",$time,pi_money_half,pi_money_one,pi_money,state,po_cola,po_money);
	  end
	  

complex_fsm complex_fsm_inst
(
    .sys_clk(sys_clk),
	 .sys_rst_n(sys_rst_n),
	 .pi_money_half(pi_money_half),
	 .pi_money_one(pi_money_one),
	 
	 .po_cola(po_cola),
	 .po_money(po_money)
);

endmodule

六、结果及仿真

1、综合器综合出的状态转移图

在这里插入图片描述
在这里插入图片描述

2、仿真波形

在这里插入图片描述
经分析,与开始手动绘制的波形图吻合,结果正确,此处不再上传上板验证结果。

七、总结

通过这两个实验,我学会了如何绘制状态转移图,如何通过状态转移图来绘制波形,并用代码实现。了解了什么是状态机,以及其应用场景:事件的处理具有前后顺序。Moore型状态机与Mealy型状态机的区别以及在状态转移图中的区别。
在用状态机来解决事件时,需要先提取三要素:输入、输出、状态,以此来绘制状态转移图,并进行化简。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值