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

【开源】分层状态机(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.xdnf.cn/news/17628.html

相关文章:

  • Loki+Alloy+Grafana构建轻量级的日志分析系统
  • 随机向量正交投影定理(Orthogonal Projection Theorem, OPT)_学习笔记
  • 【YOLO学习笔记】YOLOv11详解
  • Vue 3 快速入门 第五章
  • 强制类型转换
  • 五种 IO 模型与阻塞 IO
  • vscode uv 发布一个python包:编辑、调试与相对路径导包
  • 【代码随想录day 16】 力扣 112. 路径总和
  • printf函数格式化输出攻略
  • SQL(结构化查询语言)的四大核心分类
  • 【Jenkins入门以及安装】
  • 【unitrix数间混合计算】2.11 二进制正整数特质(bin_pos.rs)
  • 《C语言》结构体和联合体练习题--1
  • 如何回收内存对象,有哪些回收算法?
  • Fish shell的abbr命令行参数介绍和Bat文件查看工具
  • 【QT】常⽤控件详解(七)容器类控件 GroupBox TabWidget 布局管理器 Spacer
  • 深度学习-卷积神经网络CNN-AlexNet
  • LeetCode 括号生成
  • Hadoop MapReduce过程
  • LeetCode - 搜索插入位置 / 排序链表
  • (LeetCode 面试经典 150 题) 104. 二叉树的最大深度 (深度优先搜索dfs)
  • 【Docker实战入门】从核心概念到镜像构建
  • JavaScript的 fetch() 方法 笔记250810
  • CSS优先级、HTTP响应状态码
  • Android的事件分发流程、Kotlin协程、4大组件、Handler机制、架构设计、性能优化、内存泄漏
  • 第4章 程序段的反复执行2while语句P128练习题(题及答案)
  • 智慧农业-无人机视角庄稼倒伏农作物倒伏检测数据集VOC+YOLO格式541张1类别
  • VSCode添加Python、Java注释技巧、模板
  • 疏老师-python训练营-Day40训练和测试的规范写法
  • NumPy性能飞跃秘籍:向量化计算如何提升400倍运算效率?