尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

嵌入式状态机怎么写?用“洗衣机“讲清楚(附代码模板)

嵌入式状态机怎么写?用“洗衣机“讲清楚(附代码模板)
📅 发布时间:2026/7/2 8:41:21

嵌入式状态机怎么写?用"洗衣机"讲清楚(附代码模板)

一句话: 状态机能用枚举+switch-case把散乱的if-else改造成清晰的状态流转。本文用洗衣机做比喻,5分钟看懂,附可直接复用的代码模板。

单片机程序写着写着就容易乱——标志位满天飞,if-else 嵌套五六层,过两周自己都看不懂。

状态机就是来解决这个问题的。

状态机是什么?想想洗衣机

你家的全自动洗衣机,按"启动"之后是这样的:

进水 → 洗涤 → 排水 → 脱水 → 漂洗 → 排水 → 脱水 → 结束

注意两个关键点:

  1. 洗衣机一次只在一个状态——进水的时候绝不可能同时脱水
  2. 状态切换有条件——水满了才能开始洗,水排干了才能开始脱水

这就是状态机。单片机程序也是一样的道理。

没有状态机的时候,代码长什么样

void main_loop(void) { if (step == 0) { // 进水 if (water_level > FULL) { step = 1; } } else if (step == 1) { // 洗涤 if (timer > 600) { step = 2; } } else if (step == 2) { // 排水 if (water_level == 0) { step = 3; } } else if (step == 3) { // 脱水 if (timer > 300) { step = 4; } } // ... 再写 20 个 else if }

这代码能跑吗?能。好维护吗?你试试三个月后改一步逻辑——牵一发动全身。

用状态机重写

先定义状态:

typedef enum { STATE_INIT, // 初始化 STATE_IDLE, // 空闲 STATE_RUNNING, // 运行中 STATE_ERROR, // 故障 STATE_SHUTDOWN // 关机 } E_SYS_STATE;

主循环变成这样:

E_SYS_STATE g_eState = STATE_INIT; void main_loop(void) { switch (g_eState) { case STATE_INIT: init_peripherals(); g_eState = STATE_IDLE; break; case STATE_IDLE: if (start_cmd_received) { g_eState = STATE_RUNNING; } break; case STATE_RUNNING: run_task(); if (fault_detected) { g_eState = STATE_ERROR; } if (stop_cmd_received) { g_eState = STATE_SHUTDOWN; } break; case STATE_ERROR: handle_error(); if (error_cleared) { g_eState = STATE_IDLE; } break; case STATE_SHUTDOWN: power_down(); break; default: g_eState = STATE_ERROR; // 兜底:跑到不该来的地方,进故障 break; } }

对比一下:

没有状态机有状态机
当前在干什么看step变量猜看g_eState一目了然
加一个新状态改一堆 if-else加一个 case 就行
出 bug 了不知道从哪跳进来的状态切换只有一处,直接定位
三个月后维护想死还能看懂

状态切换集中管理

实际项目里,状态切换最好统一在一个地方做:

void set_state(E_SYS_STATE eNewState) { if (eNewState == g_eState) { return; // 没变化就不折腾 } // 离开旧状态前做清理 switch (g_eState) { case STATE_RUNNING: stop_all_outputs(); // 安全操作:离开运行态先关输出 break; default: break; } g_eState = eNewState; // ★ 只有这一处赋值 // 进入新状态时做初始化 switch (eNewState) { case STATE_RUNNING: reset_timers(); break; default: break; } }

好处:整个程序里状态切换只有set_state()一个入口。出 bug 的时候在这加个printf,你马上知道是谁、什么时候、切到了什么状态。

状态机 ≠ 一定要画图

很多教程一上来就甩 UML 状态图,小白看着就劝退。

其实核心就三句话:

  1. 用枚举列出所有状态——命名要能看懂,别用 0 1 2 3
  2. switch-case 处理每个状态——default 必须写,兜底
  3. 状态切换统一入口——一个函数搞定,方便调试

画不画图是次要的,先把代码写清楚。

什么时候该用状态机

场景要不要用
单个 LED 闪烁没必要,计时器+标志位够了
设备上电→自检→待机→运行→关机必须用
通信协议解析(等数据→校验→处理→应答)必须用
传感器读值+显示随便,状态不超过 3 个就算了

判断标准很简单:如果你的流程超过 3 步,或者经常在"等某个条件"和"做某件事"之间切换,用状态机。

一个容易犯的错:在状态里死等

// 错误写法:在 case 里 while 死等 case STATE_WAIT_READY: while (!device_ready()); // ← 卡死了!其他事全干不了 g_eState = STATE_NEXT; break; // 正确写法:条件不满足就走,下次循环再检查 case STATE_WAIT_READY: if (device_ready()) { g_eState = STATE_NEXT; } // 不满足就保持当前状态,主循环继续跑 break;

状态机是非阻塞的。每个状态进来,检查条件,能干就干然后切走,不能干就退出等下次循环。整个系统靠主循环的高速轮转来驱动,而不是在某个状态里死等。

总结

要点一句话
核心思想一次只在一个状态,切换有条件
实现方式枚举 + switch-case + 统一切换函数
最大禁忌在状态里 while 死等
什么时候用流程超过 3 步就用

状态机不是什么高深的玩意。说白了就是把"程序跑到哪了"这件事从一堆散乱的 if-else 里拎出来,变成一个清晰的状态变量。写起来多几行代码,调试起来省半天时间。

相关新闻

  • EastWave应用:光场与石墨烯和特异介质相互作用的研究
  • Windows 11终极瘦身指南:Win11Debloat让系统重获新生
  • 如何为Windows掌机添加完美运动控制:HandheldCompanion终极指南

最新新闻

  • 抖音下载工具终极指南:三步实现高清无水印批量下载
  • 抖音下载工具:5分钟掌握批量下载无水印视频的完整方案
  • Magisk Root终极指南:如何安全获取Android最高权限的完整教程
  • 从黑盒到白盒:构建体系化漏洞挖掘方法论与实战流程
  • ASP.NET Core 10 JwtBearer + Keycloak OIDC 本地开发 401 循环跳转排查全记录
  • 30天小白逆袭:收藏这份AI大模型学习计划,快速掌握前沿技术!

日新闻

  • Python Playwright录制功能:从零到一构建自动化测试脚本
  • 如何用开源工具永久保存你心爱的小说:novel-downloader全攻略
  • In-Context Learning不是教知识,而是模式对齐:从5个示例到100个工业级样本的真相

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号