You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Verilog电梯FSM中实现超重检测与状态切换?

电梯有限状态机(FSM)超重检测异常问题排查与修复

问题概述

使用Verilog实现包含IDLE、MOVING、ALERT、ERROR四种状态的电梯FSM,基础楼层调度功能仿真正常,但在测试超重触发ERROR状态场景时出现异常:预期电梯前往3楼过程中在2楼触发超重信号进入ERROR状态,恢复后继续运行至3楼,实际却在3楼才检测到超重,且状态在IDLE与MOVING间反复切换。

现有实现代码

测试模块

module Elevator_FSM2;

    // Input signals 
    reg clk;
    reg reset;
    reg [3:0] request_floor;
    reg over_time;
    reg over_weight;

    // Output signals
    wire [3:0] current_floor;
    wire door_alert;
    wire weight_alert;

  
    Elevator_FSM_inst uut (
        .clk(clk),
        .reset(reset),
        .request_floor(request_floor),
        .over_time(over_time),
        .over_weight(over_weight),
        .current_floor(current_floor),
        .door_alert(door_alert),
        .weight_alert(weight_alert)
    );

    
    initial clk = 0;
    always #5 clk = ~clk;  

endmodule

FSM核心模块

module Elevator_FSM_inst (
    input        clk,
    input        reset,
    input  [3:0] request_floor,
    input        over_time,
    input        over_weight,
    output reg [3:0] current_floor,
    output reg       door_alert,
    output reg       weight_alert
);
    localparam IDLE   = 2'b00,
               MOVING = 2'b01,
               ALERT  = 2'b10,
               ERROR  = 2'b11;

    reg [1:0] current_state, next_state;

    always @(posedge clk or posedge reset) begin
        if (reset)
            current_state <= IDLE;
        else
            current_state <= next_state;
    end

    always @(*) begin
        next_state = current_state;
        door_alert = 0;
        weight_alert = 0;

        case (current_state)
            IDLE: begin
                if (request_floor != 4'b0000)
                    next_state = MOVING;
            end

            MOVING: begin
                if (over_time) begin
                    door_alert = 1;
                    next_state = ALERT;
                end else if (over_weight) begin
                    weight_alert = 1;
                    next_state = ERROR;
                end else if (current_floor == request_floor) begin
                    next_state = IDLE;
                end
            end

            ALERT: begin
                if (!over_time)
                    next_state = MOVING;
            end

            ERROR: begin
                if (!over_weight)
                    next_state = MOVING;
            end
        endcase
    end

    always @(posedge clk or posedge reset) begin
        if (reset)
            current_floor <= 0;
        else if (current_state == MOVING) begin
            if (current_floor < request_floor)
                current_floor <= current_floor + 1;
            else if (current_floor > request_floor)
                current_floor <= current_floor - 1;
        end
    end
endmodule

基础功能仿真结果

Time=0 | State=00 | Floor= 0 | Request= 0 | Door=0 | Weight=0
Time=10 | State=00 | Floor= 0 | Request= 3 | Door=0 | Weight=0
Time=15 | State=01 | Floor= 0 | Request= 3 | Door=0 | Weight=0
Time=25 | State=01 | Floor= 1 | Request= 3 | Door=0 | Weight=0
Time=35 | State=01 | Floor= 2 | Request= 3 | Door=0 | Weight=0
Time=45 | State=01 | Floor= 3 | Request= 3 | Door=0 | Weight=0
Time=55 | State=00 | Floor= 3 | Request= 3 | Door=0 | Weight=0
design.sv:48: $finish called at 60 (1s)

超重测试用例与异常结果

测试用例

initial begin
    $monitor("Time=%0t | State=%b | Current Floor=%d | Request Floor=%d | Door Alert=%b | Weight Alert=%b", 
              $time, uut.current_state, current_floor, request_floor, door_alert, weight_alert);
    
    reset = 1; 
    request_floor = 4'd1; 
    over_time = 0; 
    over_weight = 0;

    #10 reset = 0;  

    #10 request_floor = 4'd3;

    #40; 
    $display("Elevator reached Floor 2. Activating over_weight signal.");
    
    over_weight = 1;
    #20; 

    $display("Elevator in ERROR state due to over_weight.");
    over_weight = 0;  

    #40;
  
    #100 $finish;
end

异常仿真结果

Time=0 | State=00 | Current Floor= 0 | Request Floor= 1 | Door Alert=0 | Weight Alert=0
Time=15 | State=01 | Current Floor= 0 | Request Floor= 1 | Door Alert=0 | Weight Alert=0
Time=20 | State=01 | Current Floor= 0 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
Time=25 | State=01 | Current Floor= 1 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
Time=35 | State=01 | Current Floor= 2 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
Time=45 | State=01 | Current Floor= 3 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
Time=55 | State=00 | Current Floor= 3 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
Elevator reached Floor 2. Activating over_weight signal.
Time=65 | State=01 | Current Floor= 3 | Request Floor= 3 | Door Alert=0 | Weight Alert=1
Time=75 | State=11 | Current Floor= 3 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
Elevator in ERROR state due to over_weight.
Time=85 | State=01 | Current Floor= 3 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
Time=95 | State=00 | Current Floor= 3 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
Time=105 | State=01 | Current Floor= 3 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
Time=115 | State=00 | Current Floor= 3 | Request Floor= 3 | Door Alert=0 | Weight Alert=0
... // 后续反复在IDLE/MOVING间切换

问题根因

  1. 测试用例时序错误:测试中#40的延时计算偏差,导致超重信号在电梯到达3楼并进入IDLE状态后才被置位,错过2楼的触发时机。
  2. FSM逻辑优先级问题:MOVING状态中,current_floor == request_floor的判断优先级高于超重检测,即使超重信号有效,只要楼层到达请求值,就会进入IDLE,忽略异常状态。
  3. 异常状态退出逻辑缺陷:ERROR状态解除后回到MOVING,但此时楼层已等于请求楼层,立刻切回IDLE,导致状态反复切换。

修复方案

1. 修正测试用例时序

调整延时,确保超重信号在电梯处于2楼时触发:

initial begin
    $monitor("Time=%0t | State=%b | Current Floor=%d | Request Floor=%d | Door Alert=%b | Weight Alert=%b", 
              $time, uut.current_state, current_floor, request_floor, door_alert, weight_alert);
    
    reset = 1; 
    request_floor = 4'd1; 
    over_time = 0; 
    over_weight = 0;

    #10 reset = 0;  

    #10 request_floor = 4'd3;

    #20; // 调整延时,对应电梯到达2楼的时序
    $display("Elevator reached Floor 2. Activating over_weight signal.");
    
    over_weight = 1;
    #20; 

    $display("Elevator in ERROR state due to over_weight.");
    over_weight = 0;  

    #40;
  
    #100 $finish;
end

2. 优化FSM状态转移逻辑

  • 调整MOVING状态判断优先级,优先处理异常信号;
  • 在ALERT/ERROR状态中保持告警输出,直到异常解除;
always @(*) begin
    next_state = current_state;
    door_alert = 0;
    weight_alert = 0;

    case (current_state)
        IDLE: begin
            if (request_floor != 4'b0000)
                next_state = MOVING;
        end

        MOVING: begin
            // 优先处理异常信号
            if (over_time) begin
                door_alert = 1;
                next_state = ALERT;
            end else if (over_weight) begin
                weight_alert = 1;
                next_state = ERROR;
            end else if (current_floor == request_floor) begin
                next_state = IDLE;
            end
        end

        ALERT: begin
            door_alert = 1; // 保持告警直到超时解除
            if (!over_time)
                next_state = MOVING;
        end

        ERROR: begin
            weight_alert = 1; // 保持告警直到超重解除
            if (!over_weight)
                next_state = MOVING;
        end
    endcase
end

修复后预期流程

  1. 电梯从0楼出发,响应3楼请求,依次到达1楼、2楼;
  2. 2楼时触发超重信号,进入ERROR状态,weight_alert持续置1;
  3. 超重信号解除后,回到MOVING状态,继续运行至3楼;
  4. 到达3楼后进入IDLE状态,流程结束。

内容的提问来源于stack exchange,提问作者Gr_10

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 12:14:50