4. 洗衣机程序状态机
任务说明
设计一个洗衣机控制程序的状态机,覆盖从启动到结束的完整洗涤流程。程序需要管理以下核心状态:注水、洗涤、漂洗、脱水,并支持用户随时暂停(暂停后可在当前阶段继续)和取消(终止程序并排水)。本案例使用C语言实现一个轻量级状态机,不依赖特定硬件平台,通过标准输入模拟用户操作,便于独立编译和验证。
状态定义与迁移逻辑
| 状态 | 触发事件 | 动作 | 下一状态 |
|---|---|---|---|
| IDLE(待机) | START | 启动注水 | FILL |
| FILL(注水) | WATER_FULL | 开始洗涤 | WASH |
| WASH(洗涤) | WASH_DONE | 开始漂洗 | RINSE |
| RINSE(漂洗) | RINSE_DONE | 开始脱水 | SPIN |
| SPIN(脱水) | SPIN_DONE | 流程结束 | COMPLETE |
| PAUSE(暂停) | RESUME | 恢复原状态 | 原状态 |
| 任意运行态 | CANCEL | 排水、停机 | IDLE |
完整实现代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum {
IDLE, FILL, WASH, RINSE, SPIN, PAUSE, COMPLETE
} State;
typedef enum {
EV_START, EV_WATER_FULL, EV_WASH_DONE, EV_RINSE_DONE,
EV_SPIN_DONE, EV_PAUSE, EV_RESUME, EV_CANCEL
} Event;
const char* state_name(State s) {
switch(s) {
case IDLE: return "IDLE(待机)";
case FILL: return "FILL(注水)";
case WASH: return "WASH(洗涤)";
case RINSE: return "RINSE(漂洗)";
case SPIN: return "SPIN(脱水)";
case PAUSE: return "PAUSE(暂停)";
case COMPLETE: return "COMPLETE(完成)";
}
return "UNKNOWN";
}
// 状态机核心:返回迁移后的新状态
State transition(State current, Event ev, State* saved_state) {
// 暂停状态特殊处理:只有RESUME和CANCEL有效
if (current == PAUSE) {
if (ev == EV_RESUME) return *saved_state;
if (ev == EV_CANCEL) return IDLE;
return current; // 其他事件在暂停时忽略
}
// 非暂停状态:若收到PAUSE,保存当前状态并进入暂停
if (ev == EV_PAUSE) {
if (current == FILL || current == WASH || current == RINSE || current == SPIN) {
*saved_state = current;
return PAUSE;
}
return current; // IDLE和COMPLETE不可暂停
}
// 取消事件:任何运行状态均可取消
if (ev == EV_CANCEL) {
if (current == FILL || current == WASH || current == RINSE || current == SPIN) {
return IDLE;
}
return current;
}
// 正常流程迁移
switch (current) {
case IDLE:
if (ev == EV_START) return FILL;
break;
case FILL:
if (ev == EV_WATER_FULL) return WASH;
break;
case WASH:
if (ev == EV_WASH_DONE) return RINSE;
break;
case RINSE:
if (ev == EV_RINSE_DONE) return SPIN;
break;
case SPIN:
if (ev == EV_SPIN_DONE) return COMPLETE;
break;
default:
break;
}
return current; // 无效事件保持原状态
}
// 模拟操作:从标准输入读取事件字符串并转换
Event parse_event(const char* cmd) {
if (strcmp(cmd, "start") == 0) return EV_START;
if (strcmp(cmd, "full") == 0) return EV_WATER_FULL;
if (strcmp(cmd, "wash_done") == 0) return EV_WASH_DONE;
if (strcmp(cmd, "rinse_done") == 0) return EV_RINSE_DONE;
if (strcmp(cmd, "spin_done") == 0) return EV_SPIN_DONE;
if (strcmp(cmd, "pause") == 0) return EV_PAUSE;
if (strcmp(cmd, "resume") == 0) return EV_RESUME;
if (strcmp(cmd, "cancel") == 0) return EV_CANCEL;
return -1; // 无效命令
}
int main() {
State current = IDLE;
State saved = IDLE; // 用于暂停时保存原状态
char cmd[32];
printf("洗衣机状态机已启动。可用命令:\n");
printf(" start | full | wash_done | rinse_done | spin_done\n");
printf(" pause | resume | cancel | quit\n");
printf("当前状态: %s\n", state_name(current));
while (1) {
printf("> ");
if (scanf("%31s", cmd) != 1) break;
if (strcmp(cmd, "quit") == 0) break;
Event ev = parse_event(cmd);
if (ev == -1) {
printf("无效命令,请重试。\n");
continue;
}
State next = transition(current, ev, &saved);
if (next != current) {
printf("[状态迁移] %s --> %s\n", state_name(current), state_name(next));
current = next;
} else {
printf("[事件被忽略] 当前状态 %s 不响应此事件。\n", state_name(current));
}
if (current == COMPLETE) {
printf("洗涤流程完成!输入 start 可开始新一轮。\n");
current = IDLE; // 自动回到待机,便于连续演示
}
}
printf("程序退出。\n");
return 0;
}
编译与运行
# 编译
gcc -o washer_fsm washer_fsm.c
# 运行
./washer_fsm
验证方法与通过标准
按以下顺序输入命令,观察状态迁移是否符合预期:
- 正常流程:依次输入
start→full→wash_done→rinse_done→spin_done,状态应依次从IDLE→FILL→WASH→RINSE→SPIN→COMPLETE,随后自动回到IDLE。 - 暂停/恢复:输入
start→full(进入WASH)→pause(进入PAUSE)→resume(应回到WASH而非其他状态)→wash_done继续后续流程。 - 取消:输入
start→pause→cancel,应从PAUSE回到IDLE;或在WASH状态直接输入cancel,应回到IDLE。 - 无效事件:在IDLE状态输入
wash_done,应提示“事件被忽略”且状态不变。
以上操作均得到与预期一致的状态输出,且程序无崩溃,即可判定通过。
关键设计说明
状态机采用二维迁移表逻辑(事件驱动+状态判断),通过 saved_state 变量记录暂停前的运行状态,确保恢复时能精确回到中断点。取消操作在任意运行态(FILL/WASH/RINSE/SPIN)或PAUSE下均直接回到IDLE,模拟排水停机。COMPLETE状态仅作为流程终点的瞬时展示,随后自动复位以便连续运行。代码不依赖任何外部库,仅使用标准输入输出,便于在任何C编译环境中直接验证。