前言
实验目标:可乐定价为2.5元一瓶,可以投0.5元和1元的硬币。投币不足2.5元,不会出可乐;超过2.5元,需要找零。
以下为状态转移图:
红色线条表示回到IDLE的三种情况。
画出波形图:
注意组合逻辑和时序逻辑。这里的money是同一时刻5毛和1块的组合逻辑,不是积累的含义。时序逻辑包含积累的含义。
一、rtl代码
module fsm2
(
input wire sys_clk,
input wire sys_rst_n,
input wire money_half,
input wire money_one,
output reg cola,
output reg money_return
);
parameter IDLE =5'b00001;
parameter HALF =5'b00010;
parameter ONE =5'b00100;
parameter ONE_HALF=5'b01000;
parameter TWO =5'b10000;
/* parameter IDLE=5'b00001,
HALF=5'b00010,
ONE=5'b00100,
ONE_HALF=5'b01000,
TWO=5'b10000; */
//组合逻辑,用assign语句进行赋值,变量类型wire型
wire [1:0] money;
reg [4:0] state;
//位拼接对money进行赋值
assign money={money_one,money_half};
//数据跳转
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
state<=IDLE;
else case(state)
IDLE :if(money==2'b01)
state<=HALF;
else if(money==2'b10)
state<=ONE;
else
state<=IDLE;
HALF :if(money==2'b01)
state<=ONE;
else if(money==2'b10)
state<=ONE_HALF;
else
state<=HALF;
ONE :if(money==2'b01)
state<=ONE_HALF;
else if(money==2'b10)
state<=TWO;
else
state<=ONE;
ONE_HALF:if(money==2'b01)
state<=TWO;
else if(money==2'b10)
state<=IDLE;
else
state<=ONE_HALF;
TWO :if((money==2'b01)||(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)
cola<=1'b0;
else if((state==ONE_HALF && money==2'b10)
||(state==TWO && money==2'b01)
||(state==TWO && money==2'b10))
cola<=1'b1;
else
cola<=1'b0;
//找零信号的赋值
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
money_return<=1'b0;
else if(state==TWO && money==2'b10)
money_return<=1'b1;
else
money_return<=1'b0;
endmodule
二、状态机视图
综合器综合出的状态转移图与绘制波形图一致。
三、测试代码
`timescale 1ns/1ns
module tb_fsm2();
reg sys_clk;
reg sys_rst_n;
reg money_half;
reg money_one;
wire cola;
wire money_return;
reg random_data;
initial
begin
sys_clk=1'b1;
sys_rst_n<=1'b0;
#20
sys_rst_n<=1'b1;
end
always #10 sys_clk=~sys_clk;
//产生随机数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
random_data<=1'b0;
else
random_data<={$random}%2;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
money_half<=1'b0;
else
money_half<=random_data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
money_one<=1'b0;
else
money_one<=~random_data;
wire [1:0] money=fsm2_inst.money;
wire [4:0] state=fsm2_inst.state;
initial
begin
$timeformat(-9,0,"ns",6);
$monitor("@time %t:money_half=%b,money_one=%b,money=%b,state=%b,cola=%b,money_return=%b",$time,money_half,money_one,money,state,cola,money_return);
end
fsm2 fsm2_inst
(
. sys_clk (sys_clk ),
. sys_rst_n (sys_rst_n ),
. money_half (money_half ),
. money_one (money_one ),
. cola (cola ),
. money_return(money_return)
);
endmodule
四、仿真结果
左边的红框是出可乐不找零的情况,右边的红框是出可乐找零(找5毛)的情况。
打印的信息中,输出与输入延迟一个时钟周期,可以参考红色方框。红色方框为买到一瓶可乐的完整过程。
其中初始状态位红色横线00001,即IDLE;输入橙色横线1元,对应状态为00100,即1元;输入黄色横线5毛,对应状态为01000,即1.5元;输入绿色横线5毛,对应状态为10000,即2元;输入蓝色横线5毛,对应状态为IDLE,此时累积为2.5元,不找零。