状态机的基本要素有 3 个,其实我们在第一节的举例中都有涉及,只是没有点明,它们是:状态、输出和输入。
1、状态:也叫状态变量。在逻辑设计中,使用状态划分逻辑顺序和时序规律。比如:设计伪随机码发生器时,可以用移位寄存器序列作为状态;在设计电机控制电路时,可以以电机的不同转速作为状态;在设计通信系统时,可以用信令的状态作为状态变量等。
2、输出:输出指在某一个状态时特定发生的事件。如设计电机控制电路中,如果电机转速过高,则输出为转速过高报警,也可以伴随减速指令或降温措施等。
3、输入:指状态机中进入每个状态的条件,有的状态机没有输入条件,其中的状态转移较为简单,有的状态机有输入条件,当某个输入条件存在时才能转移到相应的状态。
根据状态机的输出是否与输入条件相关,可将状态机分为两大类:摩尔(Moore)型状态机和米勒(Mealy)型状态机。
1.1 状态机的分类:
1、摩尔状态机:摩尔状态机的输出仅仅依赖于当前状态,而与输入条件无关。每个输出仅仅与状态相关,所以它是一个摩尔型状态
机。
2、米勒型状态机:米勒型状态机的输出不仅依赖于当前状态,而且取决于该状态的输入条件。
(老师在上课的时候讲了一个很有趣的例子,一个程序员周一到周五是工作日需要工作,周六周日则休息打游戏,程序员每日的工作状态只是与日期有关,这就是摩尔状态机,如果程序员谈恋爱了,那么他每日的状态还要考虑到对象的问题才能决定自己的状态任务,那这就是米勒型状态机
1.2 状态机的工作原理图
作业:
跑马灯流水灯verilog实现:
一段式状态机:
S1 :begin
if(time1_en)begin
led_out<=4'b1001;
state<=S2;
end
else begin
led_out<=4'b0110;
state<=S1;
end
end
S2 :begin
if(time2_en)begin
led_out<=4'b1111;
state<=S3;
end
else begin
led_out<=4'b1001;
state<=S2;
end
end
S3 :begin
if(time2_en)begin
led_out<=4'b0111;
state<=S4;
end
else begin
led_out<=4'b1111;
state<=S3;
end
end
S4 :begin
if(time1_en)begin
led_out<=4'b1011;
state<=S5;
end
else begin
led_out<=4'b0111;
state<=S4;
end
end
S5 :begin
if(time1_en)begin
led_out<=4'b1101;
state<=S6;
end
else begin
led_out<=4'b1011;
state<=S5;
end
end
S6 :begin
if(time1_en)begin
led_out<=4'b1110;
state<=S7;
end
else begin
led_out<=4'b1101;
state<=S6;
end
end
S7 :begin
if(time1_en)begin
led_out<=4'b1101;
state<=S8;
end
else begin
led_out<=4'b1110;
state<=S7;
end
end
S8 :begin
if(time1_en)begin
led_out<=4'b1011;
state<=S9;
end
else begin
led_out<=4'b1101;
state<=S8;
end
end
S9 :begin
if(time1_en)begin
led_out<=4'b0111;
state<=S10;
end
else begin
led_out<=4'b1011;
state<=S9;
end
end
S10 :begin
if(time2_en)begin
led_out<=4'b000;
state<=S10;
end
else begin
led_out<=4'b0111;
state<=IDLE;
end
end
default:begin
led_out<=4'b0000;
state<=IDLE;
end
endcase
end
end
仿真波形:
二段式状态机仿真:
`timescale 1ns / 1ps
//
// Company:
// Engineer: guoliang CLL
//
// Create Date: 2020/02/21 15:30:49
// Design Name:
// Module Name: seq_gen_fsm2
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module seq_gen_fsm2(
input clk,
input rst_n,
output reg seq
);
// state declaration
parameter s0 = 2'b0,s1 = 2'b1,s2 = 2'b10,s3 = 2'b11;
reg [1:0]c_state,n_state;
// 状态转移
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
c_state <= s0;
end
else
begin
c_state <= n_state;
end
end
// 状态转移条件+输出
always@(c_state or rst_n)
begin
if(!rst_n)
begin
n_state = s0;
end
else
begin
case(c_state)
s0:begin
n_state = s1;
seq = 1'b1;
end
s1:begin
n_state = s2;
seq = 1'b0;
end
s2:begin
n_state = s3;
seq = 1'b1;
end
s3:begin
n_state = s0;
seq = 1'b1;
end
default:begin
n_state = s0;
seq = 1'b1;
end
endcase
end
end
endmodule
三段式状态机仿真:
reg[4:0] current_state;
reg[4:0] next_state;
//第一段
always@(posedge clk_25m)begin
current_state<=next_state;
end
//第二段
always @(*)begin
if(reset)begin
next_state=IDLE;
end
else begin
case(current_state)
IDLE:begin
if(time2_en)begin
next_state=S1;
end
else begin
next_state=IDLE;
end
end
S1 :begin
if(time1_en)begin
next_state=S2;
end
else begin
next_state=S1;
end
end
S2 :begin
if(time2_en)begin
next_state=S3;
end
else begin
next_state=S2;
end
end
S3 :begin
if(time2_en)begin
next_state=S4;
end
else begin
next_state=S3;
end
end
S4 :begin
if(time1_en)begin
next_state=S5;
end
else begin
next_state=S4;
end
end
S5 :begin
if(time1_en)begin
next_state=S6;
end
else begin
next_state=S5;
end
end
S6 :begin
if(time1_en)begin
next_state=S7;
end
else begin
next_state=S6;
end
end
S7 :begin
if(time1_en)begin
next_state=S8;
end
else begin
next_state=S7;
end
end
S8 :begin
if(time1_en)begin
next_state=S9;
end
else begin
next_state=S8;
end
end
S9 :begin
if(time1_en)begin
next_state=S10;
end
else begin
next_state=S9;
end
end
S10 :begin
if(time2_en)begin
next_state=S10;
end
else begin
next_state=IDLE;
end
end
default:begin
next_state=IDLE;
end
endcase
end
end
//第三段
always@(posedge clk_25m)begin
if(reset)begin
led_out<=4'b0000;
end
else begin
case(current_state)
IDLE:begin
if(time2_en)begin
led_out<=4'b0110;
end
else begin
led_out<=4'b0000;
end
end
S1 :begin
if(time1_en)begin
led_out<=4'b1001;
end
else begin
led_out<=4'b0110;
end
end
S2 :begin
if(time2_en)begin
led_out<=4'b1111;
end
else begin
led_out<=4'b1001;
end
end
S3 :begin
if(time2_en)begin
led_out<=4'b0111;
end
else begin
led_out<=4'b1111;
end
end
S4 :begin
if(time1_en)begin
led_out<=4'b1011;
end
else begin
led_out<=4'b0111;
end
end
S5 :begin
if(time1_en)begin
led_out<=4'b1101;
end
else begin
led_out<=4'b1011;
end
end
S6 :begin
if(time1_en)begin
led_out<=4'b1110;
end
else begin
led_out<=4'b1101;
end
end
S7 :begin
if(time1_en)begin
led_out<=4'b1101;
end
else begin
led_out<=4'b1110;
end
end
S8 :begin
if(time1_en)begin
led_out<=4'b1011;
end
else begin
led_out<=4'b1101;
end
end
S9 :begin
if(time1_en)begin
led_out<=4'b0111;
end
else begin
led_out<=4'b1011;
end
end
S10 :begin
if(time2_en)begin
led_out<=4'b000;
end
else begin
led_out<=4'b0111;
end
end
default:begin
led_out<=4'b0000;
end
endcase
end
end
对比比较一下三段的区别:
1)一段式:整个状态机写到一个always模块里面,在该模块中既描述状态转移,又描述状态的输入和输出;
(2)二段式:用两个always模块来描述状态机,其中一个always模块采用同步时序描述状态转移;另一个模块采用组合逻辑判断状态转移条件,描述状态转移规律以及输出;
(3)三段式:在两个always模块描述方法基础上,使用三个always模块,一个always模块采用同步时序描述状态转移,一个always采用组合逻辑判断状态转移条件,描述状态转移规律,另一个always模块描述状态输出(可以用组合电路输出,也可以时序电路输出)。