当前位置: 首页 > news >正文

【开源】分层状态机(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

http://www.dtcms.com/a/324033.html

相关文章:

  • Loki+Alloy+Grafana构建轻量级的日志分析系统
  • aurora接口ufc控流设计
  • Rust面试题及详细答案120道(11-18)-- 控制流与函数
  • Docker 镜像常见标签(如 `标准`、`slim`、`alpine` 和 `noble`)详细对比
  • 利用 SD-WAN 技术优化机房运维与网络安全评估的最佳实践
  • 2025下半年AI技术热点全景透视:从多模态革命到具身智能爆发
  • SpringMVC的知识点总结
  • Microsoft Store​​ 总是打不开页面怎么办
  • LeetCode131~150题解
  • opencv:图像轮廓检测与轮廓近似(附代码)
  • 浏览器CEFSharp88+X86+win7 之js交互开启(五)
  • 人工智能系列(8)如何实现无监督学习聚类(使用竞争学习)?
  • Lua基础+Lua数据类型
  • Java学习第一百二十一部分——HTTP
  • 超越基础!一文掌握CNN/Transformer/MoE架构,实战多模态AI(第三章)
  • 《解锁 C++ 基础密码:输入输出、缺省参数,函数重载与引用的精髓》
  • NLP 2025全景指南:从分词到128专家MoE模型,手撕BERT情感分析实战(第四章)
  • FlinkSQL Joins全解析
  • Spring基于XML的自动装配
  • 低版本 IntelliJ IDEA 使用高版本 JDK 语言特性的问题
  • IntelliJ IDEA 2025.2 重磅发布
  • 第16届蓝桥杯Scratch选拔赛初级及中级(STEMA)2025年1月12日真题
  • 机器学习——TF-IDF 衡量词语在文档中重要程度
  • 【代码随想录day 15】 力扣 257. 二叉树的所有路径
  • LeetCode 括号生成
  • Jmeter性能测试之检测服务器CPU/Memory/磁盘IO/网络IO
  • 服务器硬件电路设计之 I2C 问答(三):I2C 总线上可以接多少个设备?如何保证数据的准确性?
  • 【Qt】QCustomPlot 简易配置教程
  • XML 指南
  • Redis一站式指南一:从MySQL事务到Redis持久化及事务实现