状态机就是一种能够描述具有逻辑顺序和时序顺序事件的方法。
状态机有两大类:Mealy型和Moore型。
Moore型状态机的输出只与当前状态有关,而Mealy型状态机的输出不仅取决于当前状态,还受到输入的直接控制,并且可能与状态无关。
下面本例程使用的为Mealy状态机,因为这样使用可以有尽可能少的状态的个数,减少内存资源的占用量。
可乐售价为2.5元
投币有两种选项:投入1元或者投入5角;
当投入综合为2.5元时出可乐,当投入总和满3元时,找零0.5元。
则状态转移图如下:
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
);
//分别用0,1,2,3,4表示状态转移图中的五个状态
parameter IDLE=3'b000,HALF=3'b001,ONE=3'b010,ONE_HALF=3'b011,TWO=3'b100;
reg [2:0] state;
wire [1:0] pi_money;
//00表示没有投入,01表示投入五角,10表示投入一元
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==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
仿真测试代码如下:
`timescale 1ns / 1ns
module tb_complex_fsm();
reg sys_clk;
reg sys_rst_n;
reg pi_money_half;
reg pi_money_one;
reg random_data;
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 #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)
pi_money_half<=1'b0;
else
pi_money_half<=random_data;
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_data;//不可能同时投入五角或者一元,所以要用取反操作
//用两根线引出来表示内部变量
wire [1:0] pi_money=complex_fsm_inst.pi_money;
wire [4:0] state=complex_fsm_inst.state;
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
vivado仿真波形图
由于时钟周期的作用,当投入五角或者一元时,输出不会立马改变,输出要等到下一个时钟周期才能产生变化。
state=0表示投入总和为0元
state=1表示投入综合为0.5元
state=2表示投入综合为1元
state=3表示投入综合为1.5元
state=4表示投入综合为2元
vivado波形缩小