目录
一、实验概述
上一篇博客实现了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型状态机的区别以及在状态转移图中的区别。
在用状态机来解决事件时,需要先提取三要素:输入、输出、状态,以此来绘制状态转移图,并进行化简。