1. 交通信号灯状态机

交通信号灯状态机 学习卡片

任务目标

实现一个交通信号灯控制器状态机,包含红灯、黄灯、绿灯三种稳定状态,按固定时间间隔自动循环切换;同时支持紧急车辆优先请求——当紧急请求到来时,无论当前处于何种状态,立即切换到绿灯并保持,紧急状态解除后恢复正常的定时切换流程。

核心设计

采用经典三状态FSM(红→绿→黄→红),每个状态持有独立的持续时间。紧急请求作为外部事件输入,将状态机强制拉入紧急绿灯模式;该模式不是第四种稳定状态,而是对绿灯状态的强制保持,紧急标志清除后立即回到正常调度。状态转移表如下:

当前状态事件动作下一状态
红灯定时器超时无绿灯
绿灯定时器超时无黄灯
黄灯定时器超时无红灯
任意状态紧急请求置位强制切绿灯,暂停正常计时绿灯(紧急保持)
紧急保持中紧急请求清除重置绿灯剩余时间绿灯(正常计时)

完整实现(C语言)

#include <stdio.h>
#include <stdbool.h>

typedef enum {
    STATE_RED,
    STATE_GREEN,
    STATE_YELLOW
} LightState;

typedef struct {
    LightState current;
    int red_duration;      // 红灯持续时间(秒)
    int green_duration;    // 绿灯持续时间(秒)
    int yellow_duration;   // 黄灯持续时间(秒)
    int timer;             // 当前状态已计时秒数
    bool emergency;        // 紧急车辆请求标志
} TrafficLightFSM;

void init_fsm(TrafficLightFSM *fsm) {
    fsm->current = STATE_RED;
    fsm->red_duration = 5;
    fsm->green_duration = 4;
    fsm->yellow_duration = 2;
    fsm->timer = 0;
    fsm->emergency = false;
}

const char* state_name(LightState s) {
    switch (s) {
        case STATE_RED:    return "红灯";
        case STATE_GREEN:  return "绿灯";
        case STATE_YELLOW: return "黄灯";
    }
    return "未知";
}

// 每秒调用一次,驱动状态机前进
void tick(TrafficLightFSM *fsm) {
    if (fsm->emergency) {
        // 紧急模式:强制绿灯,不计时
        fsm->current = STATE_GREEN;
        fsm->timer = 0;
        return;
    }

    fsm->timer++;
    int duration;
    switch (fsm->current) {
        case STATE_RED:    duration = fsm->red_duration;    break;
        case STATE_GREEN:  duration = fsm->green_duration;  break;
        case STATE_YELLOW: duration = fsm->yellow_duration; break;
    }

    if (fsm->timer >= duration) {
        // 状态切换
        switch (fsm->current) {
            case STATE_RED:    fsm->current = STATE_GREEN;  break;
            case STATE_GREEN:  fsm->current = STATE_YELLOW; break;
            case STATE_YELLOW: fsm->current = STATE_RED;    break;
        }
        fsm->timer = 0;
    }
}

// 紧急请求接口
void set_emergency(TrafficLightFSM *fsm, bool active) {
    if (active && !fsm->emergency) {
        // 紧急到达:立即切绿灯并保持
        fsm->emergency = true;
        fsm->current = STATE_GREEN;
        fsm->timer = 0;
    } else if (!active && fsm->emergency) {
        // 紧急解除:回到绿灯正常计时
        fsm->emergency = false;
        fsm->current = STATE_GREEN;
        fsm->timer = 0;
    }
}

// 简单演示:模拟20秒运行,第7秒触发紧急,第10秒解除
int main() {
    TrafficLightFSM fsm;
    init_fsm(&fsm);

    printf("时间 | 状态 | 紧急标志\n");
    printf("-----|------|---------\n");
    for (int t = 0; t < 20; t++) {
        if (t == 7)  set_emergency(&fsm, true);
        if (t == 10) set_emergency(&fsm, false);

        printf("%4d | %s | %s\n", t, state_name(fsm.current),
               fsm.emergency ? "紧急" : "正常");
        tick(&fsm);
    }
    return 0;
}

运行与验证

编译运行:

gcc -o traffic_light traffic_light.c
./traffic_light

预期输出(由代码逻辑直接推出):

时间 | 状态 | 紧急标志
-----|------|---------
   0 | 红灯 | 正常
   1 | 红灯 | 正常
   2 | 红灯 | 正常
   3 | 红灯 | 正常
   4 | 红灯 | 正常
   5 | 绿灯 | 正常
   6 | 绿灯 | 正常
   7 | 绿灯 | 紧急
   8 | 绿灯 | 紧急
   9 | 绿灯 | 紧急
  10 | 绿灯 | 正常
  11 | 绿灯 | 正常
  12 | 绿灯 | 正常
  13 | 黄灯 | 正常
  14 | 黄灯 | 正常
  15 | 红灯 | 正常
  16 | 红灯 | 正常
  17 | 红灯 | 正常
  18 | 红灯 | 正常
  19 | 红灯 | 正常

判定标准:

  • 第0~4秒为红灯,第5秒切绿灯,符合5秒红灯时长;
  • 第7秒紧急请求到达后,状态立即保持绿灯且紧急标志置位,不再计时切换;
  • 第10秒紧急解除后,绿灯重新计时4秒,第13秒切黄灯,第15秒切红灯,恢复正常循环;
  • 黄灯持续2秒后回到红灯,循环逻辑正确。

关键说明

本实现将紧急请求建模为外部事件输入而非独立状态,紧急解除后绿灯剩余时间从零重新计时,这是为简化演示而做的合理选择;实际工程中可改为保存紧急前的剩余时间以便恢复。状态机核心逻辑集中在tick()与set_emergency()两个函数中,main()仅用于验证行为,可直接替换为定时中断或RTOS任务周期调用。