【开源】分层状态机(HFSM)解析:复杂逻辑的清晰表达与FPGA实现(附完整的Verilog交通灯案例及仿真)
分层状态机设计
基础概念
分层状态机(HFSM)是传统状态机(FSM)的进阶版本,顾名思义,分层状态机本身包含子状态,即向if语法中在套入一层if语法,形成嵌套结构。
在我们后期设计更加复杂的项目时,使用分层状态机的思路做整个项目的核心是容易被人理解的,逻辑性和可维护性更强。比如下面几张图象。
传统状态机一旦状态超过5个,彼此之间的关系跳转让人看着都头疼,更别说去编写一个程序让它按照我们的想法运行起来了,但是使用分层状态机,我们可以将其分为几个大类,在每一个大类中再套用状态机进行跳转,如下图
这里将10个状态分成的3大类:家、超市、公司。这时只需求控制角色在什么时候进入到这3个大类即可。角色在某个场景里面的具体行为不需要关心。添加新状态时也只需要关心添加在那个大类中,以及与该大类中其他状态之间的转换关系,无需担心其它大类的切换。
接下来我们可以来使用分层状态机的思路来实现一个智能交通灯控制系统:
设计一个基于分层状态机的智能交通灯控制系统,具有两种顶层工作模式和多个子状态,实现道路交叉口的智能灯光控制。核心功能如下:
两种顶层工作模式:正常模式(NORMAL)和紧急模式(EMERGENCY)
正常模式下实现两条道路的交替通行,通过简单计时的方式实现信号灯的跳转
紧急模式下通过一个按钮控制,所有方向红灯闪烁,每次紧急模式持续5s后回到正常模式工作
在设计这个状态机的时候,如果使用传统状态机不好实现,因为在正常模式下的每一个状态都得指向一下紧急模式的状态,传统状态机的状态转移图如下图所示:
而如果采用分层状态机的思路,可以将整个框架分为正常模式和紧急模式两层状态,而这两个子状态不会相互并联影响,状态转移一目了然,如下图所示:
顶层存在两个状态,跳转的条件是紧急按钮是否被按下:
在正常模式的子状态中,为了简化我们的模型,状态跳转简单利用定时器,定时结束跳转下一个状态
在紧急情况下的子状态则就保留一个状态,定时结束时回到正常状态
程序设计
/** ****************************************Copyright (c)************************************ @Date: 2025-08-08 09:48:50* @LastEditTime: 2025-08-08 09:48:50* @FilePath: fileName* @Description:* Copyright (c) 2025 by 法拉不拉电, All Rights Reserved.** 哔哩哔哩:https://space.bilibili.com/500610348?spm_id_from=333.1007.0.0* *****************************************************************************************/ `timescale 1ns / 1ps module HFSM (// system signalsinput sys_clk ,input sys_rst_n ,// user signalsinput user_key ,output [2:0] A_led ,// A_led[0]: 绿灯; A_led[1]: 黄灯; A_led[2]: 红灯;output [2:0] B_led ,// B_led[0]: 绿灯; B_led[1]: 黄灯; B_led[2]: 红灯;output emergency_led // 紧急灯 ); reg [31:0] cnt ;// 计数器 reg emergency_done ;// 紧急模式完成标志 wire emergency_flag ;// 紧急模式标志 /*--------------------------------------------------*\状态机定义 \*--------------------------------------------------*/ parameter TOP_IDLE = 2'b00 ;// 顶层状态:空闲状态 parameter TOP_NORMAL = 2'b01 ;// 顶层状态:正常状态 parameter TOP_EMERGENCY = 2'b10 ;// 顶层状态:紧急状态 parameter NORMAL_IDEL = 5'b000_01;// 子状态:正常空闲 parameter A_YELLOW = 5'b000_10;// 子状态:A路黄灯 parameter A_GREEN = 5'b001_00;// 子状态:A路绿灯 parameter B_YELLOW = 5'b010_00;// 子状态:B路黄灯 parameter B_GREEN = 5'b100_00;// 子状态:B路绿灯 parameter EMERGENCY_IDEL = 3'b001 ;// 子状态:紧急空闲 parameter EMERGENCY_RED = 3'b100 ;// 子状态:紧急红灯 /*--------------------------------------------------*\寄存器定义 \*--------------------------------------------------*/ // 状态寄存器定义 reg [1:0] current_top_state ;// 顶层_当前状态寄存器 reg [1:0] next_top_state ;// 顶层_下一个状态寄存器 reg [4:0] current_normal_state ;// 正常_当前状态寄存器 reg [4:0] next_normal_state ;// 正常_下一个状态寄存器 reg [2:0] current_emergency_state ;// 紧急_当前状态寄存器 reg [2:0] next_emergency_state ;// 紧急_下一个状态寄存器 // 时间参数定义 parameter GREEN_TIME = 32'd50; // 绿灯时间5秒 parameter YELLOW_TIME = 32'd10; // 黄灯时间1秒 parameter EMERGENCY_TIME = 32'd50; // 紧急模式持续时间5秒 /*--------------------------------------------------*\顶层状态机状态跳转 \*--------------------------------------------------*/ always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) begincurrent_top_state <= TOP_IDLE;endelse begincurrent_top_state <= next_top_state;end end always @(*) begincase(current_top_state)TOP_IDLE:beginnext_top_state = TOP_NORMAL;endTOP_NORMAL:beginif(user_key) beginnext_top_state = TOP_EMERGENCY;endelse beginnext_top_state = TOP_NORMAL;endendTOP_EMERGENCY:beginif(emergency_done) beginnext_top_state = TOP_NORMAL;endelse beginnext_top_state = TOP_EMERGENCY;endenddefault:begin // 默认状态,防止综合错误,实际不会进入此状态。next_top_state = TOP_IDLE;endendcase end /*--------------------------------------------------*\正常模式状态机跳转 \*--------------------------------------------------*/ always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) begincurrent_normal_state <= NORMAL_IDEL;endelse begincurrent_normal_state <= next_normal_state;end end always @(*) beginif(current_top_state == TOP_NORMAL)begincase(current_normal_state)NORMAL_IDEL:beginnext_normal_state = A_GREEN; // 正常模式下,初始状态为A路黄灯endA_GREEN:beginif(cnt >= GREEN_TIME) beginnext_normal_state = A_YELLOW;endelse beginnext_normal_state = A_GREEN;endendA_YELLOW:beginif(cnt >= YELLOW_TIME) beginnext_normal_state = B_GREEN;endelse beginnext_normal_state = A_YELLOW;endendB_GREEN:beginif(cnt >= GREEN_TIME) beginnext_normal_state = B_YELLOW;endelse beginnext_normal_state = B_GREEN;endendB_YELLOW:beginif(cnt >= YELLOW_TIME) beginnext_normal_state = A_GREEN;endelse beginnext_normal_state = B_YELLOW;endenddefault:begin // 默认状态,防止综合错误,实际不会进入此状态。next_normal_state = NORMAL_IDEL;endendcaseend end /*--------------------------------------------------*\紧急模式状态机跳转 \*--------------------------------------------------*/ always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) begincurrent_emergency_state <= EMERGENCY_IDEL;endelse begincurrent_emergency_state <= next_emergency_state;end end always @(*) beginif(current_top_state == TOP_EMERGENCY)begincase(current_emergency_state)EMERGENCY_IDEL:beginnext_emergency_state = EMERGENCY_RED; // 紧急模式下,初始状态为红灯endEMERGENCY_RED:beginif(cnt >= EMERGENCY_TIME) beginnext_emergency_state = EMERGENCY_IDEL;endelse beginnext_emergency_state = EMERGENCY_RED;endenddefault:begin // 默认状态,防止综合错误,实际不会进入此状态。next_emergency_state = EMERGENCY_IDEL;endendcaseend end /*--------------------------------------------------*\计数器计数逻辑 \*--------------------------------------------------*/ always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) begincnt <= 32'd0;endelse if(current_top_state == TOP_NORMAL || current_top_state == TOP_EMERGENCY) beginif(current_normal_state != next_normal_state) begincnt <= 32'd0; // 如果状态发生变化,清零计数器endelse if(current_emergency_state != next_emergency_state) begincnt <= 32'd0; // 如果紧急状态发生变化,清零计数器endelse begincnt <= cnt + 1; // 否则计数器加1endendelse begincnt <= 32'd0; // 在空闲状态下清零计数器end end /*--------------------------------------------------*\紧急标志 \*--------------------------------------------------*/ always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n) beginemergency_done <= 1'b0;endelse if(current_top_state == TOP_EMERGENCY) beginemergency_done <= (cnt >= EMERGENCY_TIME);endelse beginemergency_done <= 1'b0;end end /*--------------------------------------------------*\输出逻辑 \*--------------------------------------------------*/ assign emergency_flag = (current_top_state == TOP_EMERGENCY); // 紧急模式标志 assign A_led[0] = (!emergency_flag && current_normal_state == A_GREEN) ? 1'b1 : 1'b0; // A路l绿灯 assign A_led[1] = (!emergency_flag && current_normal_state == A_YELLOW) ? 1'b1 : 1'b0; // A路黄灯 assign A_led[2] = (emergency_flag) ? 1'b1 : 1'b0; // A路红灯 assign B_led[0] = (!emergency_flag && current_normal_state == B_GREEN) ? 1'b1 : 1'b0; // B路绿灯 assign B_led[1] = (!emergency_flag && current_normal_state == B_YELLOW) ? 1'b1 : 1'b0; // B路黄灯 assign B_led[2] = (emergency_flag) ? 1'b1 : 1'b0; // B路红灯 assign emergency_led = (current_top_state == TOP_EMERGENCY); endmodule
仿真设计及时序
`timescale 1ns / 1ps module tb_HFSM; // Inputs reg sys_clk; reg sys_rst_n; reg user_key; // Outputs wire [2:0] A_led; wire [2:0] B_led; wire emergency_led; // Instantiate the Unit Under Test (UUT) HFSM uut (.sys_clk(sys_clk),.sys_rst_n(sys_rst_n),.user_key(user_key),.A_led(A_led),.B_led(B_led),.emergency_led(emergency_led) ); // Clock generation initial beginsys_clk = 0;forever #5 sys_clk = ~sys_clk; // 100MHz clock end // Test stimulus initial beginsys_rst_n = 0;user_key = 0;#20 sys_rst_n = 1;#150;user_key = 1;#200user_key = 0;#300;user_key = 1;#300user_key = 0;#300;user_key = 1;#300user_key = 0; end endmodule