状态机专题练习

一、状态机原理

(一)有限状态机

状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类:Moore状态机和Mealy状态机

(二)Moore状态机

摩尔状态机:当输出(output)只与当前状态有关时,所描述的状态机称为Moore型状态机。
在这里插入图片描述

(三)Mealy状态机

米利状态机:当输出(output)不仅与当前状态有关而且与输入(inputs)有关时,所描述的状态机称为Mealy型状态机。
在这里插入图片描述

(四)状态机描述方法

1.一段式

只有一个always块,把所有的逻辑(输入、输出、状态)都在一个always块的时序逻辑中实现。这种写法看起来很简洁,但是不利于维护,如果状态复杂一些容易出错。
在这里插入图片描述

2.两段式

有两个always 块,把时序逻辑和组合逻辑分隔开来。时序逻辑里进行当前状态和下一状态的切换,组合逻辑实现各个输入、输出以及状态判断。这种写法不仅便于阅读、理解、维护,而且利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。在两段式描述中,当前状态的输出用组合逻辑实现,可能存在竞争和冒险,产生毛刺。
在这里插入图片描述

3.三段式

有三个always块,一个采用同步时序的方式描述状态转移,一个采用组合逻辑的方式判断状态转移条件、描述状态转移规律,第三个always使用同步时序的方式描述每个状态的输出。
代码容易维护,时序逻辑的输出解决了两段式组合逻辑的毛刺问题,但是从资源消耗的角度上看,三段式的资源消耗多一些。
在这里插入图片描述

(五)状态机标准评判标准

好的状态机的标准很多,最重要的几个方面如下:
第一,状态机要安全,是指FSM不会进入死循环,特别是不会进入非预知的状态,而且由于某些扰动进入非设计状态,也能很快的恢复到正常的状态循环中来。这里面有两层含义:其一要求该FSM的综合实现结果无毛刺等异常扰动;其二要求FSM要完备,即使受到异常扰动进入非设计状态,也能很快恢复到正常状态。
第二,状态机的设计要满足设计的面积和速度的要求。
第三,状态机的设计要清晰易懂、易维护。

二、状态机状态设计

(一)实验要求

根据以下描述功能用verilog编写一段代码,并用状态机来实现该功能。
(1)状态机:实现一个测试过程,该过程包括启动准备状态、启动测试、停止测试、查询测试结果、显示测试结果、测试结束返回初始化6个状态;用时间来控制该过程,90秒内完成该过程;
(2)描述状态跳转时间;
(3)编码实现。

(二)设计思路

在这里插入图片描述

序号状态说明
S0初始化状态(initial)初始化
S1准备状态(ready)准备20秒钟
S2启动状态(start)经过18秒测试完成
S3停止状态(stop)经过25秒测试结束
S4查询状态(search)经过14秒测试结果查询
S5结果状态(display)显示8s测试结果
序号时间说明
C05s到S1状态,led0亮
C120s进入S2状态,led0,1亮
C218s进入S3状态,led0,1,2 亮
C325s进入S4状态,led0,1,2,3亮
C414s进入S5结果显示状态 ,led0,1,2,3闪烁
C58s返回S0初始化状态,led都灭

(三)实现

1.创建文件夹如下
在这里插入图片描述

(1).doc用于放置设计说明、系统框图、设计思路等文件
(2).ip用于放置ip核文件
(3).prj/par用于工程创建的路径
(4).rtl/src用于存放源文件,也就是放自己写的Verilog程序
(5).sim/tb用于存放仿真文件

2.创建项目
(1)打开Quartus Prime,选择File->New Project Wizard...创建项目
在这里插入图片描述

(2)在刚才的prj目录下创建项目
在这里插入图片描述

(3)选择Cyclone IV E系列的EPCE6F17C8
在这里插入图片描述
(4)完成
在这里插入图片描述
(5)详情如下
在这里插入图片描述
3.新建verilog文件,File->New->Verilog HDL File
在这里插入图片描述
4.代码设计模块

module test(
     input  wire         clk,
	 input  wire         rst_n,
	 
	 output wire  [3:0]  led
);
parameter   MAX_NUM = 26'd49_999_999;//记最大数,时间1s
parameter   C0 = 5'd5;//5s
parameter   C1 = 5'd20;//20s
parameter   C2 = 5'd18;//18s
parameter   C3 = 5'd25;//25s
parameter   C4 = 5'd14;//14s
parameter   C5 = 5'd8;//8s

//状态空间
parameter S0  = 3'd0;//初始状态
parameter S1  = 3'd1;//准备状态
parameter S2  = 3'd2;//启动状态
parameter S3  = 3'd3;//停止状态
parameter S4  = 3'd4;//查询状态
parameter S5  = 3'd5;//结果状态

reg  [4:0]  number;//每个模块计数
reg  [25:0] cnt;//计数寄存器
reg  [4:0]  state_time;//每个状态记录时
reg  [2:0]  flag;//状态标志

reg [2:0]   cstate;//现态
reg [3:0]   led_r;
//1秒钟计数器
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)  begin                          //按下复位键
	     cnt<=26'd0; 		  //计数器清零
    end
    else if(cnt == MAX_NUM)begin
        cnt <= 26'd0;
    end
    else begin
        cnt <= cnt + 1'd1;
	 end
end

//各模块计数器
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)  begin   	 //按下复位键
	    state_time <= 1'd0;
	 end
	 else if(cnt == MAX_NUM)begin
	     state_time <=  state_time + 1'd1;
	 end
	 else if(state_time == number)begin
	     state_time <=  1'd0;
	 end
	 else begin
	     state_time <=  state_time;
	 end
end


//状态切换
always@(posedge clk or negedge rst_n)begin
   if(!rst_n)begin
       cstate <= S0;
		 number <= C0;
		 flag <= 1'd0;
	end	
	else begin
	  case(cstate)
	    S0:begin
		   if(state_time == 3'd5&&(!flag))begin
			   cstate <= S1;
			   number <= C1;
			   flag <= flag + 1'd1;
		   end
			else begin
			   cstate <= S0;
			end
		 end
		 S1:begin
		   if(state_time == 5'd20&&(flag == 1))begin
		      cstate <= S2;
			   number <= C2;
			   flag <= flag + 1'd1;
			end
			else begin
			   cstate <= S1;
			end
		 end
		 S2:begin
		   if(state_time == 5'd18&&(flag == 2))begin
			   cstate <=S3;
			   number <= C3;
			   flag <= flag + 1'd1;
		   end
			else begin
			   cstate <= S2;
			end
		 end
		 S3:begin
		   if(state_time == 5'd25&&(flag == 3))begin
			   cstate <=S4;
			   number <= C4;
			   flag <= flag + 1'd1;
			end
			else begin
			  cstate <= S3;
			end
		 end
		 S4:begin
		   if(state_time == 5'd14&&(flag == 4))begin
			   cstate <=S5;
			   number <= C5;
			   flag <= flag + 1'd1;
			end
			else begin
			   cstate <= S4;
			end
		 end
		  S5:begin
		   if(state_time == 5'd8 &&(flag == 5))begin
			   cstate <=S0;
			   number <= C0;
			   flag <= 1'd0;
			end
			else begin
			   cstate <= S5;
			end
		 end
		 default:begin 
		      cstate <=S0;
			   number <= C0;
				flag <= 1'd0;
		 end
	  endcase
   end
end
//led灯状态
always@(posedge clk or negedge rst_n)begin
   if(!rst_n)begin
      led_r <= 4'b0000;
	end
	else begin
	   case(cstate)
		  S0:  led_r <= 4'b0001;
		  S1:  led_r <= 4'b0011;
		  S2:  led_r <= 4'b0111;
		  S3:  led_r <= 4'b1111;
		  S4:  begin
		         if(cnt == MAX_NUM)begin
					  led_r <= ~led_r;
					 end
					 else begin
					  led_r <= led_r ;
					 end
		       end
		 S5:  led_r <=4'b0000;
		 default:led_r <= 4'b0000;
		endcase
	end
end
assign led = led_r;
endmodule

5.引脚绑定
在这里插入图片描述

6.实验结果
由于实验的时间太长,为方便演示,本次实验用缩短的时间显示分别表示几个状态,
在这里插入图片描述

三、检测10010串的状态

(一)实验要求

画出可以检测10010串的状态图, 并用verilog编程实现之。

(二)设计思路

在这里插入图片描述

状态识别效果
S0-初始状态,不亮灯
S11led0亮,否则退回初始状态
S210led0,led1亮;否则退回S1上一状态
S3100led0,led1,led2亮;否则退回S2上一状态
S41001led0.led1,led2,led3亮;否则退回S3上一状态
S510010四个灯闪烁两秒后熄灭;否则退回S4上一状态

用按键KEY表示0,KEY2表示1,作为输入

(三)实现

相同的创建项目和文件夹同上**三、(三)1.2**
1.代码实现部分
(1)状态处理模块deal.v

//状态识别:10010
module deal(
    input   wire       clk, 
	 input   wire       rst_n,
    input   wire [1:0] key,
    output  wire [3:0] led 
);  
parameter MAX_NUM =26'd49_999_999;
parameter CNT_02 =24'd9_999_999;
//状态空间
parameter S0  = 3'd0;
parameter S1    = 3'd1;
parameter S2    = 3'd2;
parameter S3    = 3'd3;
parameter S4    = 3'd4;
parameter S5    = 3'd5;
reg [2:0]   cstate;
reg [25:0]  cnt_1s;
reg [23:0]  cnt_200ms;
reg [3:0]   led_r;

//计数器1s
always@(posedge clk or negedge rst_n)begin
   if(!rst_n)begin
	  cnt_1s <= 26'd0;
	end
	else if(cnt_1s == MAX_NUM)begin
	  cnt_1s <= 26'd0;
	end
	else begin
	  cnt_1s <= cnt_1s + 1'd1;
	end
end

//计数器0.2s
always@(posedge clk or negedge rst_n)begin
   if(!rst_n)begin
	  cnt_200ms <= 24'd0;
	end
	else if(cnt_200ms == CNT_02)begin
	  cnt_200ms <= 24'd0;
	end
	else begin
	  cnt_200ms <= cnt_200ms + 1'd1;
	end
end

//密码切换
always@(posedge clk or negedge rst_n)begin
   if(!rst_n)begin
      cstate <= S0;
	end	
	else begin
	  case(cstate)
	    S0:begin
		   if(key[1])begin
			  cstate <=S1;
		   end
			else if (key[0])begin
			  cstate <= S0;
			end
			else begin
			  cstate <= S0;
			end
		 end
		 S1:begin
		   if(key[0])begin
			  cstate <=S2;
		   end
			else if (key[1])begin
			  cstate <= S0;
			end
			else begin
			  cstate <= S1;
			end
		 end
		 S2:begin
		   if(key[0])begin
			  cstate <=S3;
		   end
			else if (key[1])begin
			  cstate <= S1;
			end
			else begin
			  cstate <= S2;
			end
		 end
		 S3:begin
		   if(key[1])begin
			  cstate <=S4;
		   end
			else if (key[0])begin
			  cstate <= S2;
			end
			else begin
			  cstate <= S3;
			end
		 end
		 S4:begin
		   if(key[0])begin
			  cstate <=S5;
		   end
			else if (key[1])begin
			  cstate <= S3;
			end
			else begin
			  cstate <= S4;
			end
		 end
		 S5:begin
		    if(cnt_1s == MAX_NUM)begin
	        cstate <= S0;
			 end
			else begin
			  cstate <= S5;
			end
		  end
		 default:cstate <= S0;
	  endcase
	end
end

always@(posedge clk or negedge rst_n)begin
   if(!rst_n)begin
      led_r <= 4'b0000;
	end
	else begin
	   case(cstate)
		  S0:  led_r <= 4'b0000;
		  S1:  led_r <= 4'b0001;
		  S2:  led_r <= 4'b0011;
		  S3:  led_r <= 4'b0111;
		  S4:  led_r <= 4'b1111;
		  S5:  begin
		         if(cnt_200ms == CNT_02)begin
					  led_r <= ~led_r;
					 end
					 else begin
					  led_r <= led_r ;
					 end
		       end
		  default:led_r <= 4'b0000;
		endcase
	end
end
assign led = led_r;
endmodule

(2)按键消抖模块key_debouce.v

module key_debouce(
     input    wire    clk,//1s震荡50_000_000次
	  input    wire    rst_n,
	  input    wire    key,//当前的按键取值
	  
	  output   wire     flag,//幻断抖动是否消除的标志信号,0为抖动,1为抖动结束
     output   wire     key_value//肖抖后稳定的按键值,给到蜂鸣器模块

);

parameter MAX_NUM =20'd1_000_000;

//定义20ms延迟计数器,0.02s秒,1_000_000c次
reg  [19:0]  cnt_delay; 
//寄存一次key的值,用来判断按键是否消抖成功
reg  key_reg;
reg  flag_r;
reg  key_value_r;
//20ms延时计数器
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)  begin                          //按下复位键
		  key_reg <= 1'b1;    //key变为高电平
		  cnt_delay <= 20'd0;  //计数器清零
		end
	 else begin
	     key_reg <= key;
        if(key_reg == 1'b1 && key == 1'b0 )begin//当这一次的key值和上一次的key值不相等时,证明按键状态在抖动
				cnt_delay <= MAX_NUM;//延迟计数器设置为20ms
			end
			else if(cnt_delay <= 20'd0)begin
	         cnt_delay<= 20'd0; 
	      end
			else begin
				 cnt_delay <= cnt_delay - 1'd1;//抖动结束开始递减
         end	
	end
end


always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)begin    
		  flag_r <= 1'b0;      //按键初始值为低电平
	 end
	 else if(cnt_delay == 20'd1) begin//初始赋值为0,,避免为0,倒计时20到1是20个数,倒计时结束
		  flag_r <= 1'b1;
	 end
    else  begin
		  flag_r <= 1'b0;
	 end
end	

always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)begin    
		  key_value_r <= 1'b1;       //按键初始值为低电平
	 end
	 else if(cnt_delay == 20'd1) begin//初始赋值为0,,避免为0,倒计时20到1是20个数,倒计时结束
		  key_value_r <= ~key;
	 end
    else  begin
		  key_value_r <= key_value;
	 end
end	
assign flag = flag_r;
assign key_value = key_value_r;
endmodule

(3)顶层模块check.v

module check(
     input   wire       clk,//1s震荡50_000_000次
	  input   wire       rst_n,
	  input   wire [1:0] key,//当前的按键取值
	  
     output  wire [3:0] led//肖抖后稳定的按键值,给到蜂鸣器模块

);
wire [1:0] key_value;
wire [1:0] flag;
key_debouce inst_key_debouce(
.clk        (clk),//1s震荡50_000_000次
.rst_n      (rst_n),
.key        (key[1]),//当前的按键取值
	  
.flag       (flag[1]),//幻断抖动是否消除的标志信号,0为抖动,1为抖动结束
.key_value  (key_value[1])//肖抖后稳定的按键值,给到蜂鸣器模块

);
key_debouce inst_key_debouce1(
.clk        (clk),//1s震荡50_000_000次
.rst_n      (rst_n),
.key        (key[0]),//当前的按键取值
	  
.flag       (flag[0]),//幻断抖动是否消除的标志信号,0为抖动,1为抖动结束
.key_value  (key_value[0])//肖抖后稳定的按键值,给到蜂鸣器模块

);

deal inst_deal(
.clk         (clk), 
.rst_n       (rst_n),
.key         ({(flag[1]&&key_value[1]),(flag[0]&&key_value[0])}),
.led         (led)
); 
endmodule

2.引脚绑定
在这里插入图片描述
3.结果
在这里插入图片描述

四、总结

经过一段时间对的学习,掌握了FPGA设计的基本思路和方法。本次实验用到状态机,实现不同状态的切换,可以让程序结构分明、易读易懂易排错,逻辑清晰。

五、参考资料

有限状态机

状态机,从细节出发(一段式、两段式、三段式,moore型、mealy型)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值