【开源】分层状态机(HFSM)解析:复杂逻辑的清晰表达与FPGA实现(附完整的Verilog交通灯案例及仿真)

发布于:2025-08-11 ⋅ 阅读:(21) ⋅ 点赞:(0)

分层状态机设计

基础概念

分层状态机(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 signals
    input               sys_clk         ,
    input               sys_rst_n       ,
    // user signals
    input               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) begin
    if(!sys_rst_n) begin
        current_top_state <= TOP_IDLE;
    end
    else begin
        current_top_state <= next_top_state;
    end
end
always @(*) begin
    case(current_top_state)
        TOP_IDLE:begin
            next_top_state = TOP_NORMAL;
        end
        TOP_NORMAL:begin
            if(user_key) begin
                next_top_state = TOP_EMERGENCY;
            end
            else begin
                next_top_state = TOP_NORMAL;
            end
        end
        TOP_EMERGENCY:begin
            if(emergency_done) begin
                next_top_state = TOP_NORMAL;
            end
            else begin
                next_top_state = TOP_EMERGENCY;
            end
        end
        default:begin // 默认状态,防止综合错误,实际不会进入此状态。
            next_top_state = TOP_IDLE;
        end
    endcase
end
​
​
/*--------------------------------------------------*\
                       正常模式状态机跳转
\*--------------------------------------------------*/
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        current_normal_state <= NORMAL_IDEL;
    end
    else begin
        current_normal_state <= next_normal_state;
    end
end
always @(*) begin
    if(current_top_state == TOP_NORMAL)begin
        case(current_normal_state)
            NORMAL_IDEL:begin
                next_normal_state = A_GREEN; // 正常模式下,初始状态为A路黄灯
            end
            A_GREEN:begin
                if(cnt >= GREEN_TIME) begin
                    next_normal_state = A_YELLOW;
                end
                else begin
                    next_normal_state = A_GREEN;
                end
            end
            A_YELLOW:begin
                if(cnt >= YELLOW_TIME) begin
                    next_normal_state = B_GREEN;
                end
                else begin
                    next_normal_state = A_YELLOW;
                end
            end
            B_GREEN:begin
                if(cnt >= GREEN_TIME) begin
                    next_normal_state = B_YELLOW;
                end
                else begin
                    next_normal_state = B_GREEN;
                end
            end
            B_YELLOW:begin
                if(cnt >= YELLOW_TIME) begin
                    next_normal_state = A_GREEN;
                end
                else begin
                    next_normal_state = B_YELLOW;
                end
            end
            default:begin // 默认状态,防止综合错误,实际不会进入此状态。
                next_normal_state = NORMAL_IDEL;
            end
        endcase
    end
end
​
/*--------------------------------------------------*\
                       紧急模式状态机跳转
\*--------------------------------------------------*/
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        current_emergency_state <= EMERGENCY_IDEL;
    end
    else begin
        current_emergency_state <= next_emergency_state;
    end
end
always @(*) begin
    if(current_top_state == TOP_EMERGENCY)begin
        case(current_emergency_state)
            EMERGENCY_IDEL:begin
                next_emergency_state = EMERGENCY_RED; // 紧急模式下,初始状态为红灯
            end
            EMERGENCY_RED:begin
                if(cnt >= EMERGENCY_TIME) begin
                    next_emergency_state = EMERGENCY_IDEL;
                end
                else begin
                    next_emergency_state = EMERGENCY_RED;
                end
            end
            default:begin // 默认状态,防止综合错误,实际不会进入此状态。
                next_emergency_state = EMERGENCY_IDEL;
            end
        endcase
    end
end
​
/*--------------------------------------------------*\
                       计数器计数逻辑
\*--------------------------------------------------*/
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        cnt <= 32'd0;
    end
    else if(current_top_state == TOP_NORMAL || current_top_state == TOP_EMERGENCY) begin
        if(current_normal_state != next_normal_state) begin
            cnt <= 32'd0; // 如果状态发生变化,清零计数器
        end
        else if(current_emergency_state != next_emergency_state) begin
            cnt <= 32'd0; // 如果紧急状态发生变化,清零计数器
        end
        else begin
            cnt <= cnt + 1; // 否则计数器加1
        end
    end
    else begin
        cnt <= 32'd0; // 在空闲状态下清零计数器
    end
end
/*--------------------------------------------------*\
                       紧急标志
\*--------------------------------------------------*/
always @(posedge sys_clk or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        emergency_done <= 1'b0;
    end
    else if(current_top_state == TOP_EMERGENCY) begin
        emergency_done <= (cnt >= EMERGENCY_TIME);
    end
    else begin
        emergency_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 begin
    sys_clk = 0;
    forever #5 sys_clk = ~sys_clk; // 100MHz clock
end
​
// Test stimulus
initial begin
    sys_rst_n = 0;
    user_key = 0;
    #20 sys_rst_n = 1;
    #150;
    user_key = 1;
    #200
    user_key = 0;
    #300;
    user_key = 1;
    #300
    user_key = 0;
    #300;
    user_key = 1;
    #300
    user_key = 0;
end
​
endmodule


网站公告

今日签到

点亮在社区的每一天
去签到