可乐定价为2.5元/瓶,投币可投0.5元或者1元硬币,若投入不超过2.5元,则不出可乐,若投入3元则可以出一瓶可乐,还要找回0.5元。与之前相比,这里的输入变量有时钟复位,一元输入pi_money_one,0.5元输入pi_money_half,输出为可乐po_cola和找零po_money;
输入只有两种情况,0.5元,1元;输出有三个:不出可乐/不找零,出可乐/找零,出可乐/找零
状态有五个:0,0.5,1,1.5,2,2.5,3
这里用00表示不投钱,01表示投入0.5元,10表示投入1元,还用00表示不出可乐不找零,10表示出可乐不找零,11表示即出可乐又找零。绘制状态转移图:
定义中间变量pi_money,表示投入的钱数,00表示0元,10表示投入1元,01表示0.5元。
状态变量的初始状态为IDLE,当投入1元时,状态跳转到ONE状态,不出可乐不找零即po_cola,po_money均为低电平0,再投入1元,状态跳转到TWO状态,不出可乐不找零po_cola,po_money均为低电平0,再投入1元,状态跳转到THREE状态,出可乐找零po_cola,po_money均为高电平1.....
绘制输入输出信号的波形如下图所示:
编写代码:
module complex_fsm
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire pi_money_one , //投币1元
input wire pi_money_half , //投币0.5元
output reg po_money , //po_money为1时表示找零
//po_money为0时表示不找零
output reg po_cola //po_cola为1时出可乐
//po_cola为0时不出可乐
);
parameter IDLE = 5'b00001;
parameter HALF = 5'b00010;
parameter ONE = 5'b00100;
parameter ONE_HALF = 5'b01000;
parameter TWO = 5'b10000;
reg [4:0] state; //五个状态
wire [1:0] pi_money;
//pi_money:为了减少变量的个数,我们用位拼接把输入的两个1bit信号拼接成1个2bit信号
//00表示投入0元,01表示投入了0.5元,10表示投入了1元
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) || (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 == TWO && pi_money == 2'b01) || (state == TWO &&
pi_money == 2'b10) || (state == ONE_HALF && 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
编译完成后通过综合器综合出来的状态图如图所示:
编写仿真代码查看波形:
任取一个位置分析,如图,当状态为10000即此时已经有两元了,pi_money等于10即投入了1元,此时应该输出一瓶可乐,找零0.5元,所以po_cola,po_money均信号拉高一个时钟周期,波形仿真正确。