1. 电梯控制系统状态机

电梯控制系统状态机 学习卡片

任务目标

设计并实现一个电梯控制系统的有限状态机(FSM),包含空闲(Idle)、运行(Moving)、开门(DoorOpen)、关门(DoorClosed)四个核心状态,处理楼层请求与紧急停止事件。系统需响应外部按钮请求,在状态间正确迁移,并保证紧急停止时优先进入安全状态。

状态定义与迁移逻辑

  • Idle(空闲):电梯静止在某楼层,无请求。收到楼层请求 → Moving;收到紧急停止 → 保持Idle(无动作)。
  • Moving(运行):电梯向目标楼层移动。到达目标楼层 → DoorOpen;收到紧急停止 → 紧急状态(Emergency)。
  • DoorOpen(开门):电梯门开启,等待乘客。关门超时或收到关门指令 → DoorClosed;收到紧急停止 → Emergency。
  • DoorClosed(关门):门已关闭,准备响应新请求。若有新楼层请求 → Moving;无请求 → Idle;收到紧急停止 → Emergency。
  • Emergency(紧急):紧急停止状态,电梯停止一切运动并保持门关闭。收到复位信号 → Idle。

完整实现代码

#include <stdio.h>
#include <stdlib.h>

typedef enum {
    IDLE,
    MOVING,
    DOOR_OPEN,
    DOOR_CLOSED,
    EMERGENCY
} State;

typedef enum {
    EV_FLOOR_REQUEST,   // 楼层请求
    EV_ARRIVED,         // 到达目标楼层
    EV_DOOR_TIMEOUT,    // 开门超时
    EV_CLOSE_DOOR,      // 手动关门
    EV_EMERGENCY_STOP,  // 紧急停止
    EV_RESET            // 复位
} Event;

typedef struct {
    State current_state;
    int current_floor;
    int target_floor;
} Elevator;

void init_elevator(Elevator *e) {
    e->current_state = IDLE;
    e->current_floor = 1;
    e->target_floor = 1;
}

const char* state_name(State s) {
    switch (s) {
        case IDLE: return "IDLE";
        case MOVING: return "MOVING";
        case DOOR_OPEN: return "DOOR_OPEN";
        case DOOR_CLOSED: return "DOOR_CLOSED";
        case EMERGENCY: return "EMERGENCY";
        default: return "UNKNOWN";
    }
}

void handle_event(Elevator *e, Event ev) {
    State s = e->current_state;
    printf("[%s] + ", state_name(s));

    switch (s) {
        case IDLE:
            if (ev == EV_FLOOR_REQUEST) {
                e->current_state = MOVING;
                printf("楼层请求 → MOVING\n");
            } else {
                printf("忽略事件\n");
            }
            break;

        case MOVING:
            if (ev == EV_ARRIVED) {
                e->current_state = DOOR_OPEN;
                printf("到达目标楼层 → DOOR_OPEN\n");
            } else if (ev == EV_EMERGENCY_STOP) {
                e->current_state = EMERGENCY;
                printf("紧急停止 → EMERGENCY\n");
            } else {
                printf("忽略事件\n");
            }
            break;

        case DOOR_OPEN:
            if (ev == EV_DOOR_TIMEOUT || ev == EV_CLOSE_DOOR) {
                e->current_state = DOOR_CLOSED;
                printf("关门 → DOOR_CLOSED\n");
            } else if (ev == EV_EMERGENCY_STOP) {
                e->current_state = EMERGENCY;
                printf("紧急停止 → EMERGENCY\n");
            } else {
                printf("忽略事件\n");
            }
            break;

        case DOOR_CLOSED:
            if (ev == EV_FLOOR_REQUEST) {
                e->current_state = MOVING;
                printf("新请求 → MOVING\n");
            } else if (ev == EV_EMERGENCY_STOP) {
                e->current_state = EMERGENCY;
                printf("紧急停止 → EMERGENCY\n");
            } else {
                e->current_state = IDLE;
                printf("无请求 → IDLE\n");
            }
            break;

        case EMERGENCY:
            if (ev == EV_RESET) {
                e->current_state = IDLE;
                printf("复位 → IDLE\n");
            } else {
                printf("紧急状态,仅接受复位\n");
            }
            break;

        default:
            break;
    }
}

int main() {
    Elevator elev;
    init_elevator(&elev);

    printf("初始状态: %s (楼层 %d)\n\n", state_name(elev.current_state), elev.current_floor);

    // 测试场景1:空闲 → 运行 → 开门 → 关门 → 空闲
    handle_event(&elev, EV_FLOOR_REQUEST);   // IDLE → MOVING
    handle_event(&elev, EV_ARRIVED);         // MOVING → DOOR_OPEN
    handle_event(&elev, EV_DOOR_TIMEOUT);    // DOOR_OPEN → DOOR_CLOSED
    handle_event(&elev, EV_CLOSE_DOOR);      // DOOR_CLOSED 无请求 → IDLE

    printf("\n--- 紧急停止测试 ---\n");
    handle_event(&elev, EV_FLOOR_REQUEST);   // IDLE → MOVING
    handle_event(&elev, EV_EMERGENCY_STOP);  // MOVING → EMERGENCY
    handle_event(&elev, EV_FLOOR_REQUEST);   // EMERGENCY 忽略
    handle_event(&elev, EV_RESET);           // EMERGENCY → IDLE

    printf("\n最终状态: %s\n", state_name(elev.current_state));
    return 0;
}

编译与运行

gcc -o elevator_fsm elevator_fsm.c
./elevator_fsm

验证方法与通过条件

程序输出应展示以下状态迁移序列,满足即判定通过:

初始状态: IDLE (楼层 1)

[IDLE] + 楼层请求 → MOVING
[MOVING] + 到达目标楼层 → DOOR_OPEN
[DOOR_OPEN] + 开门超时 → DOOR_CLOSED
[DOOR_CLOSED] + 手动关门 → IDLE

--- 紧急停止测试 ---
[IDLE] + 楼层请求 → MOVING
[MOVING] + 紧急停止 → EMERGENCY
[EMERGENCY] + 楼层请求 → 紧急状态,仅接受复位
[EMERGENCY] + 复位 → IDLE

最终状态: IDLE

通过条件:所有状态迁移与上述预期输出完全一致;紧急状态下非复位事件被正确忽略;最终状态回到IDLE。

状态机迁移图

IDLE MOVING DOOR_OPEN DOOR_CLOSED EMERGENCY 楼层请求 到达 超时/关门 新楼层请求 无请求 紧急停止 紧急停止 紧急停止 复位 正常迁移 紧急迁移 复位迁移

关键说明

  • 本实现使用事件驱动方式处理状态迁移,handle_event 函数为核心逻辑,通过 switch-case 结构清晰表达每个状态对事件的处理。
  • 紧急停止(EMERGENCY)状态优先级最高,一旦进入,除复位外所有事件均被忽略,符合电梯安全规范。
  • 实际工程中,楼层请求需携带目标楼层参数,本案例为聚焦FSM核心逻辑,将请求简化为无参事件;若需扩展,可在 Event 中增加参数或使用独立请求队列。