1. 交通信号灯控制

交通信号灯控制 学习卡片

任务目标

实现一个三状态交通信号灯有限状态机:红灯亮30秒 → 绿灯亮25秒 → 黄灯亮5秒 → 回到红灯,循环往复。状态切换由定时器驱动,每个状态有独立的持续时间。

核心实现

#include <stdio.h>
#include <unistd.h>

typedef enum {
    RED,
    GREEN,
    YELLOW
} LightState;

typedef struct {
    LightState current;
    int elapsed;      // 当前状态已持续秒数
    int duration;     // 当前状态总持续时间
} TrafficLightFSM;

// 状态持续时间表(秒)
static const int DURATION_TABLE[] = {
    [RED]    = 30,
    [GREEN]  = 25,
    [YELLOW] = 5
};

static const char* STATE_NAMES[] = {
    [RED]    = "红灯",
    [GREEN]  = "绿灯",
    [YELLOW] = "黄灯"
};

void fsm_init(TrafficLightFSM* fsm) {
    fsm->current  = RED;
    fsm->elapsed   = 0;
    fsm->duration  = DURATION_TABLE[RED];
}

void fsm_tick(TrafficLightFSM* fsm) {
    fsm->elapsed++;
    if (fsm->elapsed >= fsm->duration) {
        // 状态切换:RED -> GREEN -> YELLOW -> RED
        switch (fsm->current) {
            case RED:    fsm->current = GREEN;  break;
            case GREEN:  fsm->current = YELLOW; break;
            case YELLOW: fsm->current = RED;    break;
        }
        fsm->elapsed  = 0;
        fsm->duration = DURATION_TABLE[fsm->current];
    }
}

int main(void) {
    TrafficLightFSM fsm;
    fsm_init(&fsm);

    // 模拟运行 70 秒(覆盖完整一轮 30+25+5=60 秒 + 额外 10 秒)
    for (int t = 0; t < 70; t++) {
        printf("t=%2d秒: %s (已亮 %d/%d 秒)\n",
               t, STATE_NAMES[fsm.current], fsm.elapsed, fsm.duration);
        fsm_tick(&fsm);
    }
    return 0;
}

编译与运行

gcc -o traffic_light traffic_light.c
./traffic_light

验证方法

观察输出中状态切换的时间点:

  • t=0~29秒为红灯(第30秒tick后切换)
  • t=30~54秒为绿灯(第55秒tick后切换)
  • t=55~59秒为黄灯(第60秒tick后切换)
  • t=60秒起重新进入红灯,循环开始

若输出严格符合上述时间边界且状态顺序始终为“红灯→绿灯→黄灯→红灯”,则判定实现正确。

预期输出片段

t= 0秒: 红灯 (已亮 0/30 秒)
t=29秒: 红灯 (已亮 29/30 秒)
t=30秒: 绿灯 (已亮 0/25 秒)
t=54秒: 绿灯 (已亮 24/25 秒)
t=55秒: 黄灯 (已亮 0/5 秒)
t=59秒: 黄灯 (已亮 4/5 秒)
t=60秒: 红灯 (已亮 0/30 秒)
红灯 30秒 绿灯 25秒 黄灯 5秒 30秒到 25秒到 5秒到,循环

该FSM的核心逻辑集中在fsm_tick函数中:每次调用代表1秒流逝,当累计时间达到当前状态的持续时间后,按固定顺序迁移到下一状态并重置计时。状态转移表与持续时间表分离,便于后续扩展更多状态或调整时长。