fpga-状态机的设计及应用

目录

状态机的概念与分类

状态机的描述方法

交通灯控制器的设计


状态机的概念与分类

时序电路在时钟脉冲的作用下,在有限个状态之间进行转换,以完成某种特定的功能,所以将时序电路又称为有限机状态机(Finite State Machine),简称为状态机,用FSM表示。

但广义地讲,状态机不单单是指时序逻辑电路,而是指任何有逻辑顺序和时序规律的事件。

状态机有三个基本要素:状态、输出和输入。

(1) 状态: 用于划分逻辑顺序和时序规律。(2) 输出: 在某个状态下发生的特定事件。(3) 输入:状态机中进入每个状态的条件。

根据状态机的输出是否与输入有关,将状态机分为摩尔(Moore)型状态机和米里(Mealy)型状态机两大类。

一般地,Moore型状态机也可能有输入,只是输出不直接与输入信号相关,因此,在数字电路中,Moore型状态机表示为图6-3所示的结构形式,其中输出z(t)=f[s(t)],而与输入x(t)无关。

Mealy型状态机

Mealy型状态机的输出不仅依赖于当前状态,而且与输入有关。

Mealy型状态机的输出既与状态有关,也与输入有关,因此,在数字电路中,Mealy型状态机表示结构形式,其中输出z(t)=f[x(t),s(t)]。

状态机的描述方法

时序逻辑电路常用的功能描述有状态转换表、状态转换图和波形图三种方法。

以表格的形式描述时序电路的次态Q*以及外部输出信号Y与外部输入信号X和现态Q之间的关系。

状态转换图

以图形的方式描述时序电路的状态Q和输出Y在输入信号X的作用下随时钟CLK的变化关系。

用随时间变化的波形来描述在输入信号的作用下,输出Y及状态Q与时钟脉冲CLK之间的对应关系。

状态机有三种常用的表示方法:状态转换图、状态转换表和HDL描述。

状态机的HDL描述方法结构清晰,灵活规范,而且安全、高效和易于维护,因此是本章重点的讲述内容。

状态机设计的基本步骤是: (1) 定义状态; (2) 建立状态转换图; (3) 完成状态编码; (4) 应用HDL描述状态转换关系以及输出。

  1. 定义状态

由于检测器用于检测"1111"序列,所以电路需要识别和记忆连续输入1的个数,因此,预定义电路内部有S0、S1、S2、S3和S4共五个状态,其中S0表示当前还没有接收到一个1,S1表示已经接收到一个1,S2表示已经接收到两个1,S3表示已经接收到三个1,而S4表示已经接收到四个1。

  1. 建立状态转换图

状态定义完成之后,需要分析在时钟脉冲的作用下,状态转移的方向以及输出,画出状态转换图。通常从系统的初始状态、复位状态或者空闲状态开始分析,标出每个状态的转换方向、转换条件以及输出。

  1. 状态编码

在状态机设计中,建议使用参数定义语句parameter/localparam来定义状态编码,以增强代码的可阅读性。

无效状态的处理大致有如下三种方式:(1)转入空闲状态,等待下一个任务的到来(2)转入指定的状态,去执行特定任务;(3)转入预先定义的专门处理错误的状态,如预警状态等。

  1. 状态机的描述

Verilog HDL用过程语句描述状态机。由于时序电路的次态是现态以及输入的逻辑函数,因此需要将现态和输入信号作为过程的敏感事件或者边沿触发事件,结合case和if等高级程序语句等实现逻辑功能。

有限状态机的描述可采用一段式、两段式和三段式三种描述方式。

三段式状态机的描述模板如下:

// 第一个过程语句,时序逻辑,描述状态转换关系
always @ ( posedge clk or negedge rst_n )   
     if ( !rst_n )                                     // 复位信号有效时
            current_state <= IDLE;
     else  current_state <= next_state;          // 状态转换
  // 第二个过程语句,组合逻辑,描述次态
  always @ ( current_state,input_signals )       // 电平敏感条件
         case ( current_state )
             S1: if (...)  next_state = ...;       // 阻塞赋值
                 else next_state = ...; 
             S2: if (...)  next_state = ...; 
                 else next_state = ...; 
             ...... 
         default: ...;
        endcase
// 第三个过程语句描述输出(1),应用组合逻辑,阻塞赋值
always @ ( current_state,
                  input_signals )
   case ( current_state )
      S1: if ( cond_expression ) 
             out = ...;  
           else out = ...;                       
      S2: if ( cond_expression ) 
               out = ...; 
           else out = ...; 
       ......
       default: ...;         
    endcase
// 第三个过程语句描述输出(2),
应用时序逻辑,非阻塞赋值
always @ ( posedge clk or negedge rst_n )
  if ( !rst_n )                                  
     out <= ...;                        
   else
     case ( current_state )
        S1: if (cond_expression )  out <= ...; 
             else out <= ...; 
        S2: if ( cond_expression )  out <= ...; 
             else out <= ...; 
         ......
         default: ...;         
      endcase

设计例1的"1111"序列检测器,应用三段式状态机Verilog描述代码参考如下:

  module serial_detor ( input  clk,          // 检测器时钟
                          input  rst_n,        // 复位信号
                          input  x,             // 串行数据输入
                          output wire y   );   // 检测结果输出
      localparam S0 = 5'b00001,            // 状态定义及编码
                   S1 = 5'b00010,
                   S2 = 5'b00100, 
                   S3 = 5'b01000,
                   S4 = 5'b10000;
      // 内部状态变量定义
      reg [4:0] current_state,next_state;    // 现态和次态
      // 组合逻辑,定义输出
      assign y = ( current_state == S4 );         
      // 时序逻辑过程,描述状态转换
     always @( posedge clk or negedge rst_n) 
         if ( !rst_n )  current_state <= S0;
            else       current_state <= next_state;      
      //  组合逻辑过程,确定次态
      always @( current_state,x )               
         case ( current_state )
              S0 : if (x) next_state = S1; else next_state = S0;
              S1 : if (x) next_state = S2; else next_state = S0;
              S2 : if (x) next_state = S3; else next_state = S0;
              S3 : if (x) next_state = S4; else next_state = S0;
              S4 : if (x) next_state = S4; else next_state = S0;
         default : next_state = S0;
       endcase
   endmodule

将上述代码经过编译与综合后,建立向量波形文件进行功能仿真,得到的时序波形如图所示。

基于状态机设计按键消抖电路时,需要将按键的一次动作分解为:按下前、按下时、稳定期和释放时4个状态,分别用 KEY_IDLE、KEY_PRESSED、KEY_ACTIVE和 KEY_RELEASE表示。设按键输入用key_in表示,低电平有效,设计消抖时间为20ms,则按键消抖电路的状态转换关系如图所示。

应用系统函数$random产生随机整数的语法格式为: num = random%b // num为-(b-1) \~ (b-1)范围内的随机整数 num ={random}%b // num为0 ~ (b-1)范围内的随机整数

交通灯控制器的设计

交通灯控制器用于控制十字路口交通信号灯的状态,引导车辆和行人通行。交通灯控制器是时序逻辑电路,可以应用MCU/状态机设计方法实现。

设计过程:交通灯控制器应由状态控制电路和计时电路两部分构成。控制电路用于切换主、支干道绿灯、黄灯和红灯的状态,计时电路用于控制通行时间。

主支干道的绿、黄、红灯正常工作时共有四种组合,分别用S0、S1、S2和S3表示,状态的具体含义如表所示。

根据状态转换图设计交通灯控制电路的Verilog代码参考如下:

 module traffic_controller( clk,rst_n,t45,t5,t25,traffic_state,mG,mY,mR,sg,sy,sr );
     input clk,rst_n;
     input t45,t5,t25;
     output wire [3:0] traffic_state;   // 需要显示计时时间时,状态需要输出
     output reg mG,mY,mR;              // 主干道绿、黄、红灯
     output reg sg,sy,sr;                 // 支干道绿、黄、红灯
     // 状态及编码定义,一位热码方式
     localparam S0=4'b0001, S1=4'b0010, S2=4'b0100, S3=4'b1000;      
     // 内部变量定义
     reg [3:0] current_state,next_state;    // 现态和次态    
     // 状态输出描述
     assign traffic_state = current_state;
     // 时序逻辑过程,描述状态转换
     always @(posedge clk or negedge rst_n)   
        if ( !rst_n )                                 // 异步复位
            current_state <= S0;  
         else               // 状态切换
            current_state <= next_state;    
     // 组合逻辑过程,确定次态
     always @(current_state,t45,t25,t5)    
        case (current_state)
            S0 : if (t45) next_state = S1; else next_state = S0;
            S1 : if ( t5) next_state = S2; else next_state = S1;
            S2 : if (t25) next_state = S3; else next_state = S2;   
            S3 : if ( t5) next_state = S0; else next_state = S3;
       default :          next_state = S0;
       endcase
     // 组合逻辑过程,描述输出
     always @( current_state )                       
        case ( current_state )
            S0: begin
                 mG = 1; mY = 0; mR = 0;     // 主干道绿灯
                 sg = 0; sy = 0; sr = 1;  end  // 支干道红灯          
            S1: begin
                 mG = 0; mY = 1; mR = 0;     // 主干道黄灯
                 sg = 0; sy = 0; sr = 1; end   // 支干道红灯
            S2: begin
                 mG = 0; mY = 0; mR = 1;     // 主干道红灯
                 sg = 1; sy = 0; sr = 0; end    // 支干道绿灯
             S3: begin
                 mG = 0; mY = 0; mR = 1;     // 主干道红灯
                 sg = 0; sy = 1; sr = 0; end    // 支干道黄灯
        default:  begin                   // 其它取值时
                 mG = 1; mY = 0; mR = 0;
                 sg = 0; sy = 0; sr = 1; end
        endcase
 endmodule

如果不要求显示计时时间,则计时电路的设计比较简单。

取计时电路的时钟周期为5秒时,则45秒、5秒、25秒和5秒计时共需要9+1+5+1=16个时钟周期。

设计一个16进制加法计数器,状态编码为0~15。当状态为8时令t45=1,状态为9时令t5=1,状态为14时令t25=1,状态为15时令t5=1。因此,计时电路的Verilog描述参考如下:

 module traffic_timer(clk,rst_n,t45,t5,t25);
     input clk,rst_n;
     output wire t45,t5,t25;
      // 定义内部计数器
      reg [3:0] timer; 
      // 描述16进制计数器
      always @(posedge clk or negedge rst_n) 
         if (!rst_n)
             timer <= 4'd0;
          else
             timer <= timer+1'd1;
     // 描述输出
     assign t45 = ( timer == 4'd8 ) ;
     assign t5  = ( timer == 4'd9 ) || ( timer == 4'd15 ) ;
     assign t25 = ( timer == 4'd14 ) ;
 endmodule

将交通灯控制模块traffic_controller和计时模块traffic_timer连成图所示的顶层设计电路即可实现简单的交通信号灯控制器,并将时钟脉冲clk和复位信号rst_n连接在一起以控制两个子模块之间的同步。

若需要显示当前状态的剩余时间,则需要重新设计计时电路,而且主支干道计时时间(main_timer,sub_timer)的显示与状态有关。

以倒计时方式分别显示主干道和支干道状态的剩余时间时,则计时电路设计的Verilog 描述代码参考如下:

module traffic_timer (clk,rst_n,state,t45,t5,t25,main_timer,sub_timer);
    input clk;
    input rst_n;  
    input [3:0] state;                           // 状态信息,来自于traffic_controller
    output wire t45,t5,t25;                    // 计时到输出信号,用于控制状态切换
    output reg [5:0] main_timer,sub_timer;  // 主干道和支干道计时信息,用于显示
    // 状态定义及编码,独热码方式
    localparam S0=4'b0001, S1=4'b0010, S2=4'b0100, S3=4'b1000;
    // 组合逻辑,计时时间到逻辑     
    assign t45 = (state==S0) && (main_timer == 0);
    assign t5  = (main_timer == 0) && (sub_timer==0);
    assign t25 = (state==S2) && (sub_timer==0 );
    // 计时过程
    always @(posedge clk or negedge rst_n)  
       if ( !rst_n ) begin                   // 复位有效时
            main_timer <= 45;             // 从主干道通行开始
            sub_timer  <= 50; end   
         else                                 // 否则,在时钟作用下        	case ( state )                   // 分情况讨论
	    S0: if ( t45 ) begin        // 主干道通行时间到
 	            main_timer <= 4; 
	            sub_timer  <= sub_timer - 1; end
	         else begin
		 main_timer <= main_timer - 1; 
		 sub_timer  <= sub_timer - 1;  end
	    S1: if ( t5 ) begin     // 主干道停车时间到
	             main_timer <= 29; 
                         sub_timer  <= 24;  end
	         else begin
		  main_timer <= main_timer - 1; 
                          sub_timer  <= sub_timer - 1;  end
                S2: if ( t25 ) begin    // 支干道通行时间到
		  main_timer <= main_timer - 1;
		  sub_timer <= 4; end
	         else begin
		   main_timer <= main_timer - 1; 
		   sub_timer  <= sub_timer - 1;  end
               S3: if ( t5 ) begin    // 支干道停车时间到
	              main_timer <= 44;
                          sub_timer  <= 49; end
	         else begin
		   main_timer <= main_timer - 1; 
		   sub_timer  <= sub_timer - 1;  end
	   default:  begin  main_timer <= 45; 	
                                  sub_timer <= 50;  end 
           endcase
endmodule

由于计时时间是以二进制方式计数的,因此需要显示主、支干道计时时间时,还需要设计6位二进制数到两组BCD码的转换电路,才能驱动数码管进行显示。 带计时显示的交通灯控制器顶层测试电路如图所示。由按键产生脉冲,经过模块KEY_debounce消抖后作为交通灯计时电路的时钟。在计时电路traffic_timer的控制下,模块traffic_controller驱动交通灯显示状态,模块BinarytoSEG驱动数码管显示主、支干道状态的剩余时间。

相关推荐
9527华安2 小时前
FPGA实现MIPI转FPD-Link车载同轴视频传输方案,基于IMX327+FPD953架构,提供工程源码和技术支持
fpga开发·架构·mipi·imx327·fpd-link·fpd953
热爱学习地派大星3 小时前
FPGA远程升级 -- FLASH控制
fpga开发
szxinmai主板定制专家11 小时前
【国产NI替代】基于国产FPGA+兆易创新GD32F450的全国产16振动+2转速(24bits)高精度终端采集板卡
fpga开发
szxinmai主板定制专家12 小时前
【国产NI替代】基于FPGA的32通道(24bits)高精度终端采集核心板卡
大数据·人工智能·fpga开发
HIZYUAN18 小时前
AGM FPGA如何配置上拉或者下拉电阻
fpga开发
∑狸猫不是猫18 小时前
(13)CT137A- 简易音乐盒设计
fpga开发
ThreeYear_s1 天前
基于FPGA 的4位密码锁 矩阵键盘 数码管显示 报警仿真
fpga开发·矩阵·计算机外设
Anin蓝天(北京太速科技-陈)1 天前
252-8路SATAII 6U VPX高速存储模块
fpga开发
如何学会学习?1 天前
2. FPGA基础了解--全局网络
fpga开发
Anin蓝天(北京太速科技-陈)1 天前
271-基于XC7V690T的12路光纤PCIe接口卡
嵌入式硬件·fpga开发