一、IEC-61131-3 支持的语言PLC国际标准IEC-61131-3 是PLC编程的核心标准它规定 5种官方语言工业界通用① LD — Ladder Diagram梯形图电气继电器逻辑演化而来最适合 IO、互锁、安全逻辑可读性强电气工程师友好不适合复杂算法 用途IO逻辑安全联锁简单控制② FBD — Function Block Diagram功能块图模块化数据流逻辑类似 Simulink 用途PID控制回路信号处理③ ST — Structured Text结构化文本类似 Pascal / C 的高级语言支持函数、循环、复杂数据结构 用途复杂算法数据处理状态机实现 现代 PLC 项目中 ST 使用比例越来越高④ SFC — Sequential Function Chart顺序功能图专门用于 流程控制本质就是 PLC 标准化流程状态机 用途自动流程工艺步骤工站控制SFCSequential Function Chart顺序功能图是一种专门为 PLC 自动化流程设计的图形语言。它用三种元素表达设备逻辑① Step步骤② Transition转换条件③ Action动作⑤ IL — Instruction List指令表类似汇编语言已被淘汰IEC 标准已不推荐一、设计架构图① 设备模式Mode——策略层模式不属于流程限制系统运行策略它是运行规则系统。定义设备运行层级权限。定义系统权限与运行层级。思考顺序1️⃣ 正常生产需要什么模式2️⃣ 调试需要什么权限3️⃣ 维护时要禁止什么4 每个模式允许什么动作模式决定是否允许自动是否允许并行是否允许人工干预是否允许跳过工序模式 是否允许轴运动 是否允许IO动作 是否允许自动流程 用途Manual ✔ ✔ ✘ 调试Auto ✔ ✔ ✔ 正常生产Debug ✔ 部分 部分 开发调试Maintenance ✘ 部分 ✘ 维护 模式决定系统权限 必须先设计否则后期会混乱设备全局状态State↓ 反映系统运行阶段② 全局状态State——系统生命状态用于描述设备处于什么状态状态如何切换切换条件是什么控制大脑。它反映设备整体阶段状态不是流程设备始终处于某个状态。状态 含义 允许动作 退出条件Idle 空闲 等待启动 收到StartInit 初始化 回零、加载参数 完成Ready 就绪 等待自动运行 StartRun 自动运行 执行流程 完成/错误Pause 暂停 保持状态 继续/停止Stop 停止 安全停机 ResetError 错误 停止所有动作 ResetAlarm **** **** ****EStop **** **** ****Homing **** **** ****Alarm **** **** **** 状态机 整个系统骨架进入条件执行动作退出条件它决定是否允许工站执行是否允许调度是否允许恢复问自己三个问题1️⃣ 设备“静态时”有哪些状态例如Idle / Ready / Error / Stop2️⃣ 设备“运行时”有哪些状态Init / Run / Pause / Complete3️⃣ 哪些条件会触发状态变化例如Start按钮控制器完成反馈报警信号超时 设计原则✔ 状态少而清晰✔ 转换条件明确✔ 每个状态含义唯一 状态机 整个系统的“骨架”工站调度层Station Manager↓ 控制并行工站③ 工站管理层Station Manager它负责多工站并行调度工站互锁资源冲突管理同步点控制这层是流程调度层。不是步骤。例如工站A → 上料工站B → 加工工站C → 下料它们可以并行运行等待信号同步互相触发工站流程Station Sequence↓ 大步序④ 工站流程大步序 工艺流程设计Process Flow自动流程骨架每个工站都有自己的主流程上料工站Step1 等待物料Step2 夹紧Step3 完成加工工站Step1 定位Step2 加工Step3 检测这叫 Station Sequence它们是独立执行单元可以暂停可以恢复可以重跑每一步需定义触发条件执行动作完成条件超时策略✔ 设计方法工程思考顺序从工艺角度问1️⃣ 设备第一步做什么2️⃣ 做完怎么判断完成3️⃣ 下一步是什么4️⃣ 哪些步骤可并行得到流程回零 → 等待物料 → 定位 → 加工 → 检测 → 卸料 工程原则✔ 流程只描述顺序✔ 不描述控制细节✔ 不写程序逻辑 流程 工艺视角子流程Sub Sequence动作定义表Action Table↓ 小步序⑤ 子流程小步序执行手脚。每个大步骤内部会有子流程它们只是流程拆分不是状态例如Step2 夹紧├─ 打开气阀├─ 等待压力├─ 检查传感器└─ 确认完成这就是 Sub Sequence这是最实用、最容易落地的部分。动作ID 名称 执行对象 触发条件 完成条件 超时 失败处理A01 回原点 轴控制器 Init进入 所有轴到位 30s 报警A02 打开夹具 IO 流程步骤2 到位信号 5s 重试A03 激光加工 控制器 定位完成 控制器反馈完成 120s 停机 上位机实现时直接映射这些动作即可。✔ 设计方法把流程拆成 原子动作例如MoveAxisClampOnLaserFireReadSensor然后定义动作输入动作输出完成条件超时策略手动控制方式 动作 软件接口层这一步做好 上位机代码会非常清晰原子操作Action↓ 硬件控制接口⑥ 原子操作Action最底层MoveAxis()SetIO()ReadSensor()LaserOn()它们不知道流程不知道状态不知道模式它们只是硬件接口。另外有两条横向系统安全系统Safety System异常系统Alarm/Event System它们 不属于步骤而是全局监控层。二、异常处理和安全保护底线。异常和安全不属于步骤而是横向系统也就是流程系统↑异常系统跨所有工站↑安全系统最高优先级安全系统最高级负责急停门禁光栅超限硬件互锁它会直接强制停止所有工站切断动作进入安全状态安全系统 永远在流程之上恢复与安全策略Recovery Model这是区分普通程序员和工程师的关键。恢复策略模板情况 是否允许继续 恢复动作暂停恢复 ✔ 从当前步骤继续IO异常恢复 ✔ 重试动作轴错误恢复 部分 重新初始化安全错误 ✘ 必须人工确认异常系统第二级负责报警分类错误记录UI提示恢复策略它会通知状态机进入 Error通知工站停止异常系统 管理状态而不是步骤。互锁与异常设计Interlock Model工业系统最关键部分。号 条件 禁止动作 原因I01 安全门未关 禁止轴运动 安全I02 真空未建立 禁止加工 工艺要求I03 控制器报警 禁止所有动作 系统保护异常分类模板类型 例子 处理方式设备报警 轴错误 停止流程工艺报警 定位失败 重试/跳过通信异常 控制器断开 进入Error其它如门开禁止启动激光未关闭不能松夹轴未回零禁止自动气压低禁止运行三、正确的系统控制流应该是Mode↓State↓Station Manager↓Station Sequence↓Sub Sequence↓Action同时存在Safety System → 可中断一切Alarm System → 可改变State分三类思考1️⃣ 安全互锁问 哪些情况必须禁止动作例如门未关急停按下控制器报警2️⃣ 工艺互锁问 哪些条件不满足不能加工例如真空未建立工件未检测到温度未稳定3️⃣ 故障恢复问 出错后能否继续例如IO错误可恢复轴错误需初始化安全错误必须人工处理 异常设计 系统稳定性核心四、最重要的工程原则请记住① 安全永远高于流程安全不能写进步骤。② 异常不属于步骤步骤只能“发现异常”不能处理异常。③ 工站是并行单元不是步骤集合。④ 状态是系统级不是工艺级。⑤ 模式是策略级不是运行级。五、一个真实设备的软件结构应该像这样DeviceController├─ ModeManager├─ StateMachine├─ SafetyManager├─ AlarmManager├─ StationManager│ ├─ StationA│ │ └─ Sequence│ │ └─ SubSequence│ ├─ StationB│ └─ StationC└─ HardwareInterface如果你按这个结构设计✔ 并行可控✔ 安全独立✔ 异常统一✔ 工站解耦✔ 流程可维护这就是工业级设备软件的骨架。最后一句总结模式决定策略状态决定阶段工站决定并行步序决定流程操作决定动作安全决定底线六、最终设计成果你应得到这些文档1️⃣ 模式图2️⃣ 状态机图3️⃣ 流程图4️⃣ 动作表5️⃣ 互锁表6️⃣ 异常恢复表这就是完整自动化逻辑设计文档。实现技术C、PLC、控制器都只是执行这些规则。七、设计工具与方法对照表步骤 推荐工具 设计思路系统边界 draw.io 责任划分模式设计 表格 状态图 权限管理状态机 状态图 / Stateflow 系统骨架流程设计 流程图 工艺顺序动作定义 Excel 接口拆解互锁异常 Excel/FMEA 稳定性保障八、C实现状态和步序跳转的核心1.定义状态接口状态自己决定跳转。线程不关心逻辑。class IState { public: virtual ~IState() default; virtual void onEnter() {} virtual void onExit() {} // 返回下一个状态ID virtual int update() 0; };2. 定义状态机class StateMachine { std::unordered_mapint, std::unique_ptrIState states; IState* current nullptr; int currentId -1; public: void addState(int id, std::unique_ptrIState s) { states[id] std::move(s); } void setInitial(int id) { currentId id; current states[id].get(); current-onEnter(); } void update() { int next current-update(); if (next ! currentId) { current-onExit(); currentId next; current states[currentId].get(); current-onEnter(); } } };3. 线程执行器void runMachine(StateMachine sm) { while (running) { sm.update(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } 线程只调用 update() 流程逻辑完全解耦4、状态内部如何优雅跳转示例加工流程状态class ProcessState : public IState { public: int update() override { if (emergencyStop()) return STATE_ESTOP; if (!axisReady()) return STATE_WAIT_AXIS; if (processFinished()) return STATE_DONE; return STATE_PROCESS; // 保持当前 } };状态自己决定跳哪里。线程完全不知道。5、优雅实现“异常跳转”只需要在每个状态统一写if (globalError()) return STATE_ERROR; 所有状态自动支持异常跳转 不需要在线程中处理6、优雅实现“回退”状态返回目标即可if (retryCount 3) return STATE_POSITION; else return STATE_ERROR;7、优雅实现“并行流程”核心原则状态机不做耗时动作动作交给任务线程例如class WaitAxisState : public IState { public: int update() override { if (axisDone.load()) return STATE_NEXT; return STATE_WAIT_AXIS; } };轴线程独立void axisThread() { while (running) { if (needMove) { moveAxis(); axisDone true; } } } 状态机只判断事件 不执行耗时动作8、优雅实现“事件跳转”只要事件是原子变量即可std::atomicbool estop false; std::atomicbool manual false;状态里统一写if (estop) return STATE_ESTOP; if (manual) return STATE_MANUAL; 任意状态都支持跳转9、为什么这是工业最优结构因为它满足✔ 状态逻辑集中✔ 线程职责单一✔ 支持回退/跳转✔ 支持异常✔ 支持并行✔ 支持调试日志✔ 可测试✔ 可扩展10. 定义步骤接口class IStep { public: virtual ~IStep() default; virtual void onEnter() {} virtual void onExit() {} // 返回下一步ID virtual int execute() 0; };每个步骤自己决定跳转。线程不负责流程。11. 步骤管理器核心class StepEngine { std::unordered_mapint, std::unique_ptrIStep steps; IStep* current nullptr; int currentId -1; public: void addStep(int id, std::unique_ptrIStep s) { steps[id] std::move(s); } void setStart(int id) { currentId id; current steps[id].get(); current-onEnter(); } void update() { int next current-execute(); if (next ! currentId) { current-onExit(); currentId next; current steps[currentId].get(); current-onEnter(); } } };12.线程执行器void runProcess(StepEngine engine) { while (running) { engine.update(); std::this_thread::sleep_for(std::chrono::milliseconds(5)); } }线程只是调度器。13.步骤内部优雅跳转方式示例1顺序跳转class Step_Load : public IStep { public: int execute() override { if (!materialReady()) return STEP_WAIT; startClamp(); return STEP_MOVE; } };示例2异常跳转class Step_Move : public IStep { public: int execute() override { if (estop) return STEP_ERROR; if (axisDone()) return STEP_PROCESS; return STEP_MOVE; } };示例3回退跳转class Step_Process : public IStep { int retry 0; public: int execute() override { if (processOK()) return STEP_UNLOAD; if (retry 3) return STEP_MOVE; // 回退 return STEP_ERROR; } };为什么这才叫“优雅跳转”因为✔ 跳转逻辑写在步骤里✔ 线程完全不知道流程✔ 支持任意跳转✔ 支持回退✔ 支持异常✔ 支持插入步骤✔ 支持配置化流程14.如何实现“动态流程” 更高级如果你不想写死return STEP_MOVE;可以用 流程表驱动struct Transition { int successNext; int failNext; };步骤只返回结果enum StepResult { STEP_OK, STEP_FAIL, STEP_BUSY };然后引擎决定跳转int result current-execute(); if (result STEP_OK) next trans[currentId].successNext; 这就是 数据驱动流程引擎工业 MES / 半导体设备常用。15.如何避免线程阻塞关键步骤不能做耗时动作❌ 错误moveAxis(); while(!axisDone()) {}✔ 正确startMove(); if (axisDone()) return NEXT; else return CURRENT; 步骤是“轮询判断器”不是执行器。16、如果流程很复杂并行步骤可以运行多个 StepEnginethread1 → 机械流程thread2 → 激光流程thread3 → 通讯流程再用事件同步。这就是 多流程引擎架构很多半导体设备都这样做。17、总结一句最关键的话线程不控制流程线程只是执行器。步骤决定跳转一旦做到这一点✔ 流程会变得极清晰✔ 跳转完全自由✔ 异常处理自然存在✔ 代码结构像 PLC 一样稳定这才是真正工业级实现。18、状态跳转和步骤跳转的核心代码是一样的其它驱动状态和步骤变换的方案方案 优雅程度 工程难度 适合场景状态机/步骤机 ⭐⭐ 低 小设备数据驱动流程 ⭐⭐⭐ 中 可配置设备协程流程 ⭐⭐⭐⭐⭐ 中 上位机控制最推荐行为树 ⭐⭐⭐⭐⭐ 高 复杂机器人/多流程设备九、核心的三张表动作表步骤表异常表一、① 动作表模板Action Table 作用定义设备“能做什么” 上位机最终调用的就是这些动作ActionID 动作名称 执行对象 输入参数 成功条件 失败条件 超时 是否可重试 备注A01 回零 控制器 无 所有轴到位 控制器报警 30s 否 初始化A02 打开夹具 IO 无 到位信号ON 信号异常 5s 是 装料A03 定位工件 控制器 位置ID 控制器完成 定位失败 15s 是 加工前A04 激光加工 控制器 程序号 控制器结束 报警 120s 否 主工艺 原则一个动作 一个原子操作不要写流程只定义接口 动作表 上位机接口层设计二、② 步骤表模板Step Table 作用定义自动运行流程 比流程图更清晰、更可实现StepNo 步骤名称 执行动作 前置条件 完成条件 失败处理 超时处理 下一步 备注1 初始化 A01 回零 Start命令 动作成功 进入Error 报警 2 开机2 等待物料 无 物料传感器ON 信号稳定 等待 报警 3 装料3 定位 A03 定位工件 物料就绪 动作成功 重试2次 报警 4 关键4 加工 A04 激光加工 定位完成 控制器结束 停机 报警 5 主工艺5 卸料 A02 打开夹具 加工完成 信号到位 重试 报警 1 循环 原则✔ 每一步只做一件事✔ 必须有完成条件✔ 必须有失败策略✔ 必须有超时策略 步骤表 自动运行核心逻辑三、③ 互锁与异常表模板Interlock Table 作用保证设备不会误动作 这是稳定性的关键InterlockID 条件 禁止动作 影响范围 恢复方式 优先级 备注I01 安全门未关 禁止所有轴运动 全局 关门复位 高 安全I02 真空未建立 禁止加工 加工流程 真空建立 中 工艺I03 控制器报警 禁止所有动作 全局 Reset 高 必须原则✔ 所有安全条件必须列出✔ 所有互锁必须可解释✔ 恢复方式必须明确 互锁表 系统稳定性保障四、三张表之间的关系关键理解动作表 定义设备能力步骤表 定义流程顺序互锁表 定义安全边界五、工程建议非常重要在真正项目中✔ 先写动作表✔ 再写步骤表✔ 最后写互锁表不要直接画流程图。流程图只用于展示这三张表才用于实现。六、确保三张表的完整性出现遗漏容易补充1、先说结论工程经验自动化设计不可能完全不遗漏关键是让遗漏 能被快速发现、可局部修复、不会连锁崩塌所以重点不是“避免遗漏”而是✔ 可追踪✔ 可验证✔ 可扩展2、如何保证三张表尽量不遗漏设计阶段核心方法只有 3 个方法①用“场景驱动检查法”最有效不要只看表本身要用 设备运行场景去推演。可以逐条问开机时会发生什么用户点暂停会发生什么通信断开会发生什么物料缺失会发生什么急停恢复会发生什么然后检查 这些场景在三张表里有没有对应逻辑如果没有就是遗漏。这方法比看流程图有效 10 倍。方法②用“逆向推导法”从最终目标反推。例如目标设备稳定运行反问稳定需要什么得到能停机能恢复能报警能继续再问这些在表里有没有定义没有 → 就是遗漏。方法③用“三表交叉校验法”三张表必须互相能映射。检查规则✔ 动作表 vs 步骤表问 步骤里用到的动作动作表是否存在若步骤引用不存在动作设计有漏洞。✔ 步骤表 vs 状态机问 每个步骤在哪个状态执行若步骤没有状态归属系统会乱。✔ 互锁表 vs 动作表问 所有危险动作是否有互锁限制若某动作没有安全约束就是隐患。3、如何保证遗漏能快速处理工程关键真正成熟设计不是没有漏洞是漏洞不会引发重构。关键做 3 件事。方法①让步骤表支持“插入步骤”如果流程写死1 → 2 → 3 → 4 → 5新增步骤会崩。但若流程结构是StepID / NextStep就可以 插入新步骤 修改跳转关系无需改系统架构。这叫✔ 可扩展流程模型方法②动作接口必须稳定若动作接口稳定即使流程变化 不需要改底层代码例如新增工艺步骤只需新增Step 调用某动作。而不是写新控制逻辑。方法③互锁设计必须集中管理互锁若写在各流程里新增安全规则会爆炸。正确做法统一 InterlockManager新增互锁只需添加一条规则系统自动生效。这叫✔ 安全策略集中化4、真正保证设计可靠的终极方法不是图不是表而是 仿真推演做 3 种推演。✔ 推演 1正常运行流程模拟启动 → 运行 → 完成 → 循环检查是否有卡死步骤是否有无出口状态✔ 推演 2异常中断流程模拟运行中 → 断电运行中 → 急停运行中 → 通信断开检查是否能进入 Error是否能恢复✔ 推演 3用户乱操作模拟Run 时点 StopPause 时点 ResetError 时点 Start如果这些行为没有定义就说明设计不完整。5、工程上最强的做法高级团队用叫做 逻辑测试用例表像软件测试一样。编号 场景 期望行为 覆盖表项T01 Run时急停 进入Error 状态机T02 无物料启动 阻止运行 互锁T03 加工失败 重试或报警 步骤表只要每条用例都能找到 表中对应逻辑设计就可靠。6、总结一句工程真理自动化设计的可靠性不来自❌ 图画得多漂亮❌ 表写得多详细而来自✔ 场景推演✔ 交叉校验✔ 可扩展结构✔ 集中化策略只要做到这四点 遗漏不会消失但不会造成灾难这才是工业级设计。怎样评估 状态机的完整性异常处理的合理性。动作接口的清晰性用状态机控制流程而不是流程控制状态机具体什么意思一、如何评估【状态机的完整性】状态机完整性的本质只有一句话任何时刻设备都必须处于一个确定状态并且有合法去向评估时按这 5 条检查。✔ 1. 是否覆盖所有运行阶段问自己设备可能经历哪些阶段开机初始化待机运行暂停停止异常恢复 如果状态机里缺任何一个就是不完整。典型错误没有 Pause 状态没有 Recover 状态Error 直接回 Idle这些都会导致逻辑漏洞。✔ 2. 每个状态是否都有“出口”检查方式拿一张状态图逐个问 如果当前在这个状态可能发生什么例如Ready 状态- Start- Stop- Error 如果某状态没有任何出口程序会卡死。✔ 3. 是否有“非法输入处理”例如设备正在 Run用户突然点 Reset。状态机必须定义 是否允许 转到哪里 是否先停机 没有这些规则状态机会乱跳。✔ 4. 是否区分“系统状态”和“流程步骤”很多人混淆Step 3定位中这不是状态机状态而是流程内部阶段。状态机只描述Idle / Run / Pause / Error 状态机是“设备层级” 步骤是“工艺层级”✔ 5. 是否能从任何状态安全停止工业系统最关键 从任何状态必须能进入 Stop 或 Error 如果有状态不能停机就是危险设计。七、如何评估【异常处理的合理性】异常设计最常见问题 只考虑“报错”没考虑“恢复”评估时按这 4 条。✔ 1. 每个动作是否有三种结果一个动作执行后必须有成功失败超时 如果缺任何一种逻辑会出现悬空。✔ 2. 是否区分错误类型异常必须分类安全错误必须停机工艺错误可重试通信错误可恢复 如果所有错误都进入 Error设备会频繁停机。✔ 3. 是否定义恢复路径问Error → 怎么回 RunPause → 怎么继续通信断开 → 怎么重连 没有恢复路径只能重启设备。这就是很多设备不稳定的原因。✔ 4. 是否避免“隐式恢复”例如轴未到位 → 自动重新发送指令这就是隐式恢复容易导致无限重试机械损坏状态不同步恢复必须 显式、可控、可记录。八、如何评估【动作接口的清晰性】动作接口清晰的标准只有 3 条。✔ 1. 动作是否“原子”原子动作 只做一件事。正确MoveAxisClampOnLaserStart错误PrepareAndProcessWorkpiece这种接口会 混入流程逻辑后期无法维护。✔ 2. 动作是否“无状态”动作接口不应该判断流程修改状态机决定下一步动作只负责 执行硬件命令并返回结果否则 层级混乱。✔ 3. 动作是否有统一返回模型推荐统一返回SuccessFailTimeout不要每个动作自己定义结果否则流程层会混乱。九、最关键问题什么叫“状态机控制流程而不是流程控制状态机”这句话是自动化软件设计的分水岭。我用两个架构对比给你看。❌ 错误结构流程控制状态机很多人这样写Step 1 → MoveHome → 状态RunStep 2 → WaitSensor → 状态RunStep 3 → Error → 状态Error也就是说 流程代码决定设备状态问题流程跳转时状态乱Pause / Stop 很难插入异常处理混乱无法多流程共存这是初级自动化结构。✔ 正确结构状态机控制流程正确逻辑是状态机决定系统行为流程只是状态下的任务结构应是系统状态 Run↓Run状态允许执行流程↓流程执行 Step 3↓若发生错误↓状态机转 Error关键点 状态机拥有最高控制权流程只是被调度。用现实比喻理解流程 工人任务清单状态机 工厂管理制度工人不能决定是否停产是否进入维护是否安全检查这些由制度决定。同样 流程不能决定设备状态 状态机必须控制流程正确的软件层级应该是状态机层最高权力↓流程执行层↓动作接口层而不是流程层↓随便改状态十、工程总结最重要真正成熟的自动化系统满足✔ 状态机完整任何情况都有归属状态✔ 异常有恢复路径不是只会报警✔ 动作接口原子化不混入流程逻辑✔ 状态机控制流程不是流程控制系统做到这四点 系统基本不会崩十一、 评审设计时检查✔ 每个状态都有出口✔ 每个流程有结束条件✔ 每个动作有反馈✔ 每个错误有处理方式