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任务周期调用。