3. 交通信号灯状态机
任务说明
构建一个交通信号灯FSM,包含红、黄、绿三种常规状态及闪烁模式(黄灯闪烁,用于夜间或故障),支持定时自动切换,并支持外部触发的紧急模式(红灯常亮,禁止通行)。
状态定义与迁移
- 常规循环:红(5s) → 绿(4s) → 黄(2s) → 红,循环往复。
- 闪烁模式:黄灯以1s间隔闪烁(亮0.5s/灭0.5s),不参与常规循环。
- 紧急模式:红灯常亮,忽略定时迁移,直到紧急信号解除。
- 模式切换:
emergency信号置位时进入紧急模式;flash信号置位时进入闪烁模式;两个信号均无效时回到常规循环(从红灯开始)。
核心代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef enum { RED, GREEN, YELLOW, FLASH, EMERGENCY } State;
typedef enum { TIMER_EXPIRED, EMERGENCY_ON, EMERGENCY_OFF, FLASH_ON, FLASH_OFF } Event;
typedef struct {
State state;
int timer; // 剩余秒数
int flash_toggle; // 闪烁亮/灭标志
} FSM;
void init(FSM *fsm) {
fsm->state = RED;
fsm->timer = 5;
fsm->flash_toggle = 0;
}
void handle_event(FSM *fsm, Event ev) {
switch (fsm->state) {
case RED:
if (ev == TIMER_EXPIRED) { fsm->state = GREEN; fsm->timer = 4; }
break;
case GREEN:
if (ev == TIMER_EXPIRED) { fsm->state = YELLOW; fsm->timer = 2; }
break;
case YELLOW:
if (ev == TIMER_EXPIRED) { fsm->state = RED; fsm->timer = 5; }
break;
case FLASH:
if (ev == FLASH_OFF) { fsm->state = RED; fsm->timer = 5; }
break;
case EMERGENCY:
if (ev == EMERGENCY_OFF) { fsm->state = RED; fsm->timer = 5; }
break;
default: break;
}
// 模式切换优先级:紧急 > 闪烁 > 常规
if (ev == EMERGENCY_ON) { fsm->state = EMERGENCY; fsm->timer = -1; }
else if (ev == FLASH_ON && fsm->state != EMERGENCY) {
fsm->state = FLASH; fsm->timer = 1;
}
}
void tick(FSM *fsm) {
if (fsm->state == EMERGENCY) return; // 紧急模式不计时
if (fsm->state == FLASH) {
fsm->flash_toggle = !fsm->flash_toggle;
handle_event(fsm, fsm->flash_toggle ? FLASH_ON : FLASH_OFF);
return;
}
fsm->timer--;
if (fsm->timer <= 0) handle_event(fsm, TIMER_EXPIRED);
}
void print_state(FSM *fsm) {
const char *name[] = {"RED", "GREEN", "YELLOW", "FLASH", "EMERGENCY"};
if (fsm->state == FLASH)
printf("%s (%s)\n", name[fsm->state], fsm->flash_toggle ? "ON" : "OFF");
else
printf("%s (timer=%d)\n", name[fsm->state], fsm->timer);
}
int main() {
FSM fsm;
init(&fsm);
printf("初始状态: ");
print_state(&fsm);
// 模拟10秒常规运行
for (int i = 0; i < 10; i++) {
sleep(1);
tick(&fsm);
printf("t=%d: ", i+1);
print_state(&fsm);
}
// 触发紧急模式
printf("\n-- 紧急模式 --\n");
handle_event(&fsm, EMERGENCY_ON);
print_state(&fsm);
sleep(2);
tick(&fsm); // 紧急模式下tick不改变状态
print_state(&fsm);
// 解除紧急,进入闪烁
printf("\n-- 闪烁模式 --\n");
handle_event(&fsm, EMERGENCY_OFF);
handle_event(&fsm, FLASH_ON);
for (int i = 0; i < 4; i++) {
sleep(1);
tick(&fsm);
print_state(&fsm);
}
// 恢复正常
printf("\n-- 恢复正常 --\n");
handle_event(&fsm, FLASH_OFF);
print_state(&fsm);
return 0;
}
编译与运行
gcc -o traffic_light traffic_light.c
./traffic_light
验证方法
- 常规循环:观察前10秒输出,状态应按 RED→GREEN→YELLOW→RED 顺序迁移,且各状态持续秒数与定义一致(红5s、绿4s、黄2s)。
- 紧急模式:触发后状态显示EMERGENCY,即使调用tick(),状态仍保持EMERGENCY不变。
- 闪烁模式:解除紧急并开启闪烁后,状态在FLASH(ON)与FLASH(OFF)之间交替,每秒切换一次。
- 恢复正常:关闭闪烁后回到RED状态,定时器重置为5,重新进入常规循环。
预期输出(节选)
初始状态: RED (timer=5)
t=1: RED (timer=4)
t=2: RED (timer=3)
t=3: RED (timer=2)
t=4: RED (timer=1)
t=5: GREEN (timer=4)
t=6: GREEN (timer=3)
t=7: GREEN (timer=2)
t=8: GREEN (timer=1)
t=9: YELLOW (timer=2)
t=10: YELLOW (timer=1)
-- 紧急模式 --
EMERGENCY (timer=-1)
EMERGENCY (timer=-1)
-- 闪烁模式 --
FLASH (ON)
FLASH (OFF)
FLASH (ON)
FLASH (OFF)
-- 恢复正常 --
RED (timer=5)
关键说明
- 紧急模式优先级最高,
tick()中直接返回,不进行任何状态迁移。 - 闪烁模式通过
flash_toggle翻转产生亮/灭效果,每次tick()触发一次翻转。 - 模式解除后统一回到红灯状态,保证安全起始条件。