有限状态机 FSM——Finite State Machine

有限状态机

  • 1.状态机的结构
  • 2.Mealy状态机和Moore状态机
  • 3.用Verilog来描述可综合的状态机
  • 实例
    • 序列检测器
    • ADC采样控制电路
    • 按键消抖

1.状态机的结构

有限状态机 FSM——Finite State Machine_第1张图片
其中F和G是两个有关状态的函数,状态寄存器一般是采用正跳边沿触发的D触发器,n个触发器最多记住2^n个状态。

2.Mealy状态机和Moore状态机

上图是Mealy状态机,其输出不仅取决于当前状态还受输入的影响,Moore状态机的输出仅取决于当前状态。

3.用Verilog来描述可综合的状态机

二进制编码:所需寄存器数量少,但是用的组合逻辑多;
独热码:占用寄存器数量多,速度快,每次仅需判断一位,组合逻辑少;
格雷码:按顺序每次只变化一位的话,就用格雷码;
4个数,
二级制:00 01 10 11;
独热码:0001 0010 0100 1000;
寄存器数量多了,可能会有多余状态,记得添加default语句;

一般的三段式状态机:

  1. 写出状态转移逻辑;
  2. 时钟状态,复位信号;
  3. 输出赋值;

实例

序列检测器

检测输入为1101 ,每次输入一位din

module seq_det(
	input clk,
	input rst,
	input din,
	output reg out
);
parameter idle = 5'd0,
		  s1   = 5'd1,
		  s2   = 5'd2,
		  s3   = 5'd3,
		  s4   = 5'd4;
reg[2:0] cur_state;
reg[2:0] next_state;

always@(posedge clk,posedge rst)
begin
	if(rst)
	cur_state<=5'd0;
	else
	cur_state<=next_state;
end

always@(*)
begin
	case(cur_state)
	idle:
		if(din==1'b1)
			next_state=s1;
		else
			next_state=idle;
	s1:
		if(din==1'b1)
			next_state=s2;
		else
			next_state=idle;
	s2:
		if(din==1'b0)
			next_state=s3;
		else
			next_state=s2;
	s3:
		if(din==1'b1)
			next_state=s4;
		else
			next_state=idle;
	s4:
		if(din==1'b1)
			next_state=s1;
		else
			next_state=idle;
	
	default:next_state=idle;
	endcase
always@(*)begin
	if(cur_state==s4)
	sout=1'b1;
	else
	sout=1'b0;
	end
	
endmodule

ADC采样控制电路

ADC:模数转换,将模拟信号变成数字信号,便于数字设备处理。有限状态机 FSM——Finite State Machine_第2张图片
其中ale 是模拟端的输入选通信号,start为启动信号,eoc是转换进行中信号,转换结束oe输出使能端有效;

module adc_trans(
	input clk,rst,
	input start,eoc,
	input[7:0] data,
	output ale,oe,
	output [2:0]addr
);

parameter idle =2'b00,
		  s1   =2'b01,
		  s2   =2'b10,
		  s3   =2'b11;
reg [1:0] cur_state,next_state;
always@(posedge clk,posedge rst)begin
	if(rst)
	cur_state<=idle;
	else
	cur_state<=next_state;
end

always@(*)begin
	case(cur_state)
	idle:
		ale=0;start=0;oe=0;
		next_state=s1;
	s1:
		ale=1;start=1;oe=0;
		next_state=s2;
	s2:
		ale=0;start=0;oe=0;
		if(eoc==1)
			next_state=s3;
		else
			next_state=s2;
	s3:
		ale=0;start=0;oe=1;
		next_state=idle;
	endcase
end

endmodule

按键消抖

按键消抖的原因和原理不多赘述,直接写主要就是状态机的转换,理解了这一点就可以了。
由于这里的输入信号key_in 是异步信号,不依赖于clk;不处理会出现时序违例,常见方法是直接打两拍;
边沿检测
检测上升下降沿的原理就是利用了寄存器当前状态的输入即为下一时钟的输出;
若现在为0,下一时刻为1,就是上升沿;
若现在为1,下一时刻为0,就是下降沿;

always@(posedge clk,posedge rst)begin
	if(rst)
	key_in_edge_tem1<=1'b0;
	key_in_edge_tem2<=1'b0;
	else
	key_in_edge_tem1<=key_instable;
	key_in_edge_tem2<=key_in_edge_tem1;
end
assign nedge=!(key_in_edge_tem1)&&(key_in_edge_tem2);  //1到0  下降沿
assign pedge=(key_in_edge_tem1)&&!(key_in_edge_tem2);  //0到1  上升沿

整体的代码,其中key_flag key_state 可以不管,只是为了反馈状态添加的;方便判断状态

module debounce(
	input clk,
	input rst,
	input key_in,
	output reg key_flag,      //flag  代表 f的状态;  在f1/f2 flag为1,其他状态为0
	output reg key_state      //state 代表在f1 :0  or  f2:1
);
//其中Key_flag为是否稳定按下的标志,key_state为按下/释放的标志
reg key_in_1;
reg key_in_2;
reg key_in_stable;
reg key_in_edge_tem1;
reg key_in_edge_tem2;
wire pedge;
wire nedge;
reg[18:0] cnt;    //2^19*50MHz ==10.48576ms
reg       cnt_en;
reg       cnt_full;
parameter idle  =2'd0,
		  f1    =2'd1,
		  down  =2'd2,
		  s2    =2'd3;
reg [1:0] state;
reg [1:0] n_state;


///===========================input reg==================================
always@(posedge clk,posedge rst)begin
	if(rst)
	key_in_1<=1'b0;
	key_in_2<=1'b0;
	else
	key_in_1<=key_in;
	key_in_2<=key_in_1;
end
assign key_in_stable=key_in_2;

///============================detect egde============================
always@(posedge clk,posedge rst)begin
	if(rst)
	key_in_edge_tem1<=1'b0;
	key_in_edge_tem2<=1'b0;
	else
	key_in_edge_tem1<=key_instable;
	key_in_edge_tem2<=key_in_edge_tem1;
end
assign nedge=!(key_in_edge_tem1)&&(key_in_edge_tem2);  //1到0  下降沿
assign pedge=(key_in_edge_tem1)&&!(key_in_edge_tem2);  //0到1  上升沿

///=============================cnt==================================	
always@(posedge clk,posedge rst)begin
	if(rst)
	cnt<=19'b0;
	else(cnt_en)
	cnt<=cnt+1'b1;
	else
	cnt<= 19'b0;
end
always@(posedge clk,posedge rst)begin
	if(rst)
	cnt_full<=1'b0;
	else if(cnt==19'h7FFFF)
	cnt_full<=1'b1;
	else
	cnt_full<=1'b0;
end
///=============================fsm================================
always@(posedge clk,posedge rst)begin
	if(rst)
	state<=idle;
	else
	state<=n_state;
end
always@(*)begin
	
	case(state)
	idle:
	begin
		if(nedge)
			n_state=f1;
			cnt_en=1'b1;
		else
			n_state=idle;
	end
	
	f1:
	begin
	if(pedge)
		n_state=idle;
		cnt_en=1'b0;
	else if(cnt_full)
		key_flag=1'b1;
		key_state=1'b0;
		n_state=down;
		cnt_en=1'b0;
	else
		n_state=f1;
	end
	
	down:
	begin 
		key_flag=1'b0;  //只保持一个时钟周期的高脉冲
	if(pedge)
		n_state=f2;
		cnt_en=1'b1;
	else
		n_state=down;
	end
	
	f2:
	if(nedge)
		cnt_en=1'b0;
		n_state=down;
	else if(cnt_full)
		n_state=idle;
		cnt_en=1'b0;
		key_flag=1'b1;
	    key_state=1'b1;
	else
		n_state=f2;
	default :
		key_flag=1'b0;
		key_state=1'b1;
		cnt_en=1'b0;
		state=idle;
endcase 
endmodule

你可能感兴趣的:(FPGA,状态机,verilog)