状态机
理论学习
状态机简写为FSM(Finite State Machine),也称为同步有限状态机,我们一般简称为状态机,之所以说“同步”是因为状态机中所有的状态跳转都是在时钟的作用下进行的,而“有限”则是说状态的个数是有限的。状态机根据影响输出的原因分为两大类,即Moore型状态机和Mealy型状态机,其共同点 是:状态的跳转都只和输入有关。区别主要是在输出的时候:若最后的输出只和当前状态有关而与输入无关则称为Moore型状态机;若最后的输出不仅和当前状态有关还和输入有关则称为Mealy型状态机。状态机是时序逻辑电路中非常重要的一个应用,常在大型复杂的系统中使用较多。
实战演练
设计需求
实现一个可乐机,每次可以投1元或者0.5元,当可乐机中有2.5元时,可以取出一瓶可乐。当可乐机中有3元时,可以取一瓶可乐并找零0.5元。
程序框图
状态转移图与波形图绘制
1、输入:投入0.5元硬币、投入1元硬币;
2、输出:不出可乐/不找零、出可乐/不找零、出可乐/找零;
3、状态:可乐机中有0元、可乐机中有0.5元、可乐机中有1元、可乐机中有1.5元、可乐机中有2元、可乐机中有2.5元、可乐机中有3元。
状态转移图:
波形图
代码编写
module complex_fsm
(
input clk,reset,pi_money_half,pi_money_one,
output reg po_cola,
output reg po_money
);
parameter IDLE = 5'b00001;
parameter HALF = 5'b00010;
parameter ONE = 5'b00100;
parameter ONE_HALF = 5'b01000;
parameter TWO = 5'b10000;
wire[1:0] pi_money;
reg [4:0] state;
assign pi_money = {pi_money_one,pi_money_half};
always @(posedge clk or negedge reset)
if(reset == 1'b0)
state <= IDLE;
else
case(state)
IDLE:
if(pi_money == 2'b01)
state <= HALF;
else if(pi_money == 2'b10)
state <= ONE;
else if(pi_money == 2'b00)
state <= IDLE;
else
state <= state;
HALF:
if(pi_money == 2'b01)
state <= ONE;
else if(pi_money == 2'b10)
state <= ONE_HALF;
else if(pi_money == 2'b00)
state <= HALF;
else
state <= state;
ONE:
if(pi_money == 2'b01)
state <= ONE_HALF;
else if(pi_money == 2'b10)
state <= TWO;
else if(pi_money == 2'b00)
state <= ONE;
else
state <= state;
ONE_HALF:
if(pi_money == 2'b01)
state <= TWO;
else if(pi_money == 2'b10)
state <= IDLE;
else if(pi_money == 2'b00)
state <= ONE_HALF;
else
state <= state;
TWO:
if(pi_money == 2'b01 || pi_money == 2'b10)
state <= IDLE;
else if(pi_money == 2'b00)
state <= TWO;
else
state <= state;
default: state <= IDLE;
endcase
// 输出可乐信号
always @(posedge clk or negedge reset)
if(reset == 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 clk or negedge reset)
if(reset == 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 1 ns/ 1 ns
module complex_fsm_vlg_tst();
reg clk;
reg pi_money_half;
reg pi_money_one;
reg reset;
wire[4:0] state = i1.state;
wire[1:0] pi_money = i1.pi_money;
wire po_cola;
wire po_money;
complex_fsm i1 (
// port map - connection between master ports and signals/registers
.clk(clk),
.pi_money_half(pi_money_half),
.pi_money_one(pi_money_one),
.po_cola(po_cola),
.po_money(po_money),
.reset(reset)
);
initial
begin
clk = 1'b1;
reset <= 1'b0;
#20
reset <= 1'b1;
end
always #10 clk = ~clk;
always @(posedge clk or negedge reset)
if(reset == 1'b0)
begin
pi_money_half = 1'b0;
pi_money_one = 1'b0;
end
else
begin
pi_money_half = {$random} % 2;
if(pi_money_half == 1'b0)
pi_money_one = {$random} % 2;
else
pi_money_one = 1'b0;
end
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
endmodule