ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从梯形图到ST:三菱FX3U设备控制框架与FB功能块实战

从梯形图到ST:三菱FX3U设备控制框架与FB功能块实战 做设备控制这行的谁不是从梯形图过来的。梯形图看着直观排查故障时顺着触点一路看下去很舒服但真到了要搭一套稍微复杂的设备控制框架——多个电机、阀门、自动流程揉在一起——梯形图就变成了蜘蛛网加一个条件得改三行动一个流程得拆一大片。后来我在三菱FX3U上改用ST编程才真正体会到结构化写设备控制的效率。这篇文章是我用三菱FX3U从零搭一套设备控制框架的完整记录核心是ST程序架构和FB功能块的落地用法全程实战适合已经有一定PLC基础、准备从梯形图向结构化编程进阶的同行。我会把完整的IO规划、程序分区、ST语法要点、电机和阀门FB的代码、自动流程状态机的写法全部分享出来还把实际调试过程中踩过的坑一并列上。这套方法在两三台中小型设备上验证过稳定性和可维护性都比传统梯形图方案强一个档次。如果你手里正好有FX3U的项目准备重新组织程序结构或者不想再用难维护的梯形图写顺序控制这篇内容应该能帮你省下不少摸索时间。1. 为什么用ST搭控制框架从梯形图到结构化编程1.1 梯形图在复杂控制场景下的痛点梯形图的优势是每一位触点、每一个线圈都看得见摸得着。一台简易设备一台电机加两个按钮梯形图三五行就能搞定现场电工也能直接看图排查。可一旦设备流程复杂起来问题就来了。我在做一个热压设备项目时深有体会。设备里有主电机、进给电机、两个气动阀门、一组加热管自动流程要按“开阀→启动电机→延时→加压→保压→泄压→停止”的顺序跑。梯形图写这个顺序控制要么用一堆置位复位指令外加中间继电器要么用SFC。置位复位写多了程序里的逻辑状态全靠脑子硬记某个状态忘了复位设备就卡死在中途。现场调起来一个个辅助继电器翻地址头皮发麻。梯形图的另一个痛点是流程修改的成本高。今天工艺说阀门2要和电机1同时启动明天说改成阀门2先启动2秒每次改动都要牵扯好几段梯形图程序稍不留神就会把别的逻辑带崩。这种改动方式在小项目里忍忍就过去了但想搭一套可以复用的设备控制框架梯形图根本撑不住。1.2 ST语言的优势与FX3U的适用性ST结构化文本是IEC 61131-3标准的五种PLC编程语言之一。它本质上是给PLC用的高级编程语言有变量声明、IF条件判断、CASE分支、FOR循环函数和功能块这些概念跟写C语言、Python的思维模式很接近。ST语言在复杂控制场景下最核心的优势是结构性。设备运行的每一个状态、每一个步骤都可以显式地表达出来不会像梯形图那样把状态藏在无数个辅助继电器的置位复位里。自动流程用CASE语句写状态机每一步做什么、什么时候切换下一步、异常怎么退出一眼就能看明白。改动流程时只动CASE里的某一步其他逻辑不受影响。很多工程师有个误区觉得三菱FX3U是老一代小型机只能写梯形图。实际上GX Works3软件完全支持对FX3U使用ST语言编程虽然FX3U的ST能力和FX5U、iQ-R系列比有差距复杂数据类型和高级函数支持有限但做常规设备控制框架完全够用。FX3U的定位是中小型设备控制而中小型设备恰恰是ST能发挥最大价值的地方——IO点几十个、流程控制多、逻辑嵌套深用梯形图难写用ST刚好。1.3 这套框架能解决什么问题我从实践中总结下来一套基于ST和FB的设备控制框架能解决三类问题。一是程序可读性问题。用ST把程序按功能区隔开输入映射、设备控制、流程管理、报警处理各有各的段落新同事接手时不用从头到尾翻梯形图直接看流程那一块就能理解设备怎么动作。二是逻辑复用问题。设备上的电机、阀门、加热器本质上都是同一类控制对象只是参数不同。把电机控制逻辑做成FB功能块每台电机调用一个实例启动、停止、故障、复位逻辑全部封装在FB内部。新增一台电机只需要拖一个FB实例再配置好对应的输入输出点不需要重写逻辑。三是修改维护问题。工艺要求变了改对应FB的参数或者改CASE里对应的步骤就行不是像梯形图那样从一堆触点里“考古”。这一点在设备交付后期尤其重要客户三天两头提需求变化程序改得动、改得快就是实实在在的工程能力。2. 框架整体设计IO规划、程序分区与执行模型2.1 一个典型设备的IO点表规划搭框架之前先把IO规划好。我用一个中小型热压设备做例子说明包含2台电机、2个气动阀门、1组加热器这是非常典型的设备配置。规划IO时先把输入输出分开输入按按钮、传感器、保护反馈分类输出按执行机构分类。输入点位软元件说明信号类型急停按钮X0常闭触点断开表示急停安全信号模式选择开关X1ON为自动OFF为手动状态信号启动按钮X2上升沿有效操作信号停止按钮X3上升沿有效操作信号复位按钮X4上升沿有效操作信号电机M1热继电器X5常闭触点断开表示过载保护反馈电机M2热继电器X6常闭触点断开表示过载保护反馈阀门V1开到位X7磁性开关到位反馈阀门V1关到位X10磁性开关到位反馈阀门V2开到位X11磁性开关到位反馈阀门V2关到位X12磁性开关到位反馈加热器超温保护X13常闭触点断开表示超温保护反馈输出点位软元件说明负载类型电机M1接触器Y0驱动电机M1接触器线圈电机M2接触器Y1驱动电机M2接触器线圈阀门V1开Y2电磁阀V1开方向电磁阀线圈阀门V1关Y3电磁阀V1关方向电磁阀线圈阀门V2开Y4电磁阀V2开方向电磁阀线圈阀门V2关Y5电磁阀V2关方向电磁阀线圈加热器输出Y6驱动加热器接触器/固态继电器三色灯-运行Y7设备运行指示信号灯三色灯-报警Y10设备报警指示信号灯这个点表规划有两个原则值得注意。第一个原则是保护反馈尽量用常闭触点接法用“断开表示故障”而不是“接通表示故障”。这样做的好处是断线时系统会自动识别为故障状态不会出现传感器线掉了设备还在闷头运行的安全隐患。第二个原则是IO规划要给未来留余量X点、Y点不要刚好用完留出四五个备用后面客户要加传感器、加指示灯才不会抓瞎。2.2 程序分区思路初始化、运行周期与报警FX3U的程序是一个循环扫描的过程每扫描一次执行一遍程序。我把设备控制框架的程序分成几个明确的区域每个区域职责单一、固定执行顺序。第一个区域是输入映射区。把X点的物理信号复制到对应的全局标签上比如急停按钮X0映射到标签bEMG模式开关X1映射到标签bModeAuto。这样做的原因是后面程序里使用的都是符号名不直接引用软元件地址程序的可读性和可维护性大幅提升。现场如果改了接线只需要改映射区这一行不用去翻整个程序。第二个区域是设备控制区。这个区域调用各种FB功能块电机FB、阀门FB、加热器FB全部在这里实例化并驱动。FB内部封装了启动、停止、故障保持、复位这些逻辑外部只负责给命令和接收状态。第三个区域是流程管理区。自动模式下的顺序控制逻辑放在这里用CASE语句实现状态机根据工艺步骤依次给设备控制区的FB下发命令。这个区域是ST编程发挥最大价值的地方梯形图写顺序控制要几十行ST只需要一个清晰的CASE块。第四个区域是报警处理区。收集所有FB里产生的报警信号加上急停、超温等系统级报警统一进行锁存、指示灯输出、触屏显示映射。报警区和设备控制区分开排查问题时就能顺着“报警是哪来的—哪个FB报的—现场什么信号触发”这条线查。2.3 FX3U循环扫描与ST的执行顺序理解FX3U的程序执行方式对写ST至关重要。FX3U的CPU按照从左到右、从上到下的顺序执行ST程序每一行代码都在每个扫描周期内执行一次。这意味着你在ST程序里写的赋值、判断都是按照书写顺序实时生效的。有一个细节要特别注意ST程序中如果在前面给某个输出标签赋值TRUE后面又根据条件给它赋值FALSE那么最终输出的结果是最后一次赋值的结果。这和梯形图里“线圈重复输出”的情况是一样的属于程序员的逻辑责任范畴。我在搭建框架时尽量保持每个输出标签在程序里只被赋值一次所有的条件判断都在赋值之前预先算好这样程序逻辑清晰不会出现“改了前面忘了后面”的隐性覆盖问题。另一个要注意的是FX3U的ST程序执行时不同程序块之间按工程配置中的执行顺序执行不是并行的。设备控制区会先于流程管理区执行所以流程管理区里发出的命令在当前扫描周期内立刻就能被设备控制区接收并响应但FB的输出状态更新要等到下一个扫描周期才能被流程管理区读取到这是PLC扫描的固有特性写状态机切换时心里要始终有这个概念。3. ST编程环境搭建与语言要点3.1 GX Works3中创建ST程序块使用ST语言对FX3U编程需要用到三菱的GX Works3软件。打开工程后在导航窗口的“程序”区域右键选择新建程序编程语言选“ST”程序类型选“结构化文本”确认后在程序编辑器里就可以直接编写ST代码了。在GX Works3中FX3U的ST程序可以独立成块也可以混编在梯形图程序中比如在梯形图的某个步进块里嵌入ST代码。我的习惯是整个程序都用ST组织梯形图只保留最外层的主程序框架这样的好处是程序风格统一不会出现一会儿梯形图一会儿ST的割裂感。GX Works3中还有一个核心概念叫“全局标签”。全局标签可以理解成整个工程里的公共变量它在标签编辑器里创建可以指定对应的软元件地址也可以让编译器自动分配地址。我的框架里大量使用全局标签IO信号、控制命令、报警标志都在全局标签里统一定义。这个环节建议在写代码之前先做把标志位规划好后面写程序就不用一边写一边回来建标签了。3.2 ST核心语法变量声明、赋值、IF/CASE、定时器ST语言的语法和高级语言接近但有PLC的独特规则。变量声明在程序的开始部分FX3U的ST里常见的数据类型有BOOL、INT、DINT、WORD、REAL、TIME。布尔量表示开关信号整数用于步进状态、计数器浮点数用于模拟量处理。变量声明的写法如下VAR_GLOBAL g_bStartBtn : BOOL; (* 启动按钮 *) g_bStopBtn : BOOL; (* 停止按钮 *) g_bEMG : BOOL; (* 急停状态 *) g_nAutoStep : INT; (* 自动流程步号 *) END_VAR注释用括号星号包裹和梯形图的注释风格完全不同写习惯了会觉得比梯形图的注释更灵活。赋值语句用冒号等号和标准ST一致。条件判断有IF和CASE两种。IF适合条件少、逻辑分支不复杂的情况CASE适合多步状态切换也就是状态机的场景。定时器是PLC编程绕不开的内容。FX3U的ST中可以直接调用TON、TOF、TP等定时器功能块。TON通电延时定时器的用法如下(* 定义定时器实例 *) VAR tonDelay : TON; END_VAR (* 调用定时器 *) tonDelay(IN : g_bStartBtn, PT : T#5S); IF tonDelay.Q THEN // 5秒延时到达后的逻辑 END_IF;PT参数是设定时间T#5S表示5秒。FX3U的定时器资源是有限的普通定时器有几十路累计定时器也有数量限制写程序时要留意不要在FB里无节制地使用定时器实例。3.3 标签与软元件地址的绑定策略在GX Works3中全局标签可以和软元件地址绑定。比如我要把X0这个物理输入绑定到标签g_bEMG上可以在标签编辑器里直接指定软元件X0程序里只用标签名。我的建议是设备控制逻辑里全部用标签名不直接写X、Y这些硬地址。这样做的好处很直接如果现场因为接线变更换了输入点只需要改标签编辑器里对应的一行绑定程序本体完全不用动。设想一下如果程序里几十处都直接写X5现场把热继电器反馈从X5挪到X12你得全文搜索X5替换还要担心误替换这种体验在调试现场真的太痛苦了。局部变量和FB内部变量不需要绑定软元件地址编译器会自动分配FX3U的内部资源。所以FB功能块是天然可复用的内部状态变量不需要占用你的IO点也没有地址冲突的顾虑。这一点是我在FB上花精力研究的直接原因——写一个通用性好的FB后续项目只需要重复拖拽实例配置好每一个实例的IO和参数就行。4. FB功能块详解从电机控制到顺序流程4.1 FB与FC的区别、何时用FB在IEC 61131-3标准里程序组织单元分三类程序PRG、功能块FB、函数FC。FB和FC最容易混淆它们都是可以封装逻辑的代码块核心区别在于是否有内部状态保持能力。FB功能块每次调用时都有自己的实例实例内部可以保存状态变量。比如电机控制FB内部有一个“运行保持”的BOOL变量代表了当前电机是否处于运行状态这个变量在FB的两次调用之间会保持住不会丢失。FC函数则不能保存内部状态输入相同、输出就相同没有记忆能力。简单类比FB是有档案的工作人员你问他事情他会根据自己手头的记录回答FC是个计算器每次按键相同出来的结果就相同。在设备控制里几乎所有的控制对象都是有记忆的。电机需要保持运行、阀门需要保持开状态、设备的流程需要记住当前跑到哪一步所以这些逻辑都应该封装成FB。FC更多用于纯计算场景比如模拟量换算、数据处理、数学计算。4.2 手写一个电机控制FBMTR_CTRL电机控制是设备控制里最基础也最重要的FB。现场应用中电机控制不只是一路输出那么简单还涉及启动和停止命令、热继电器保护、急停联动、报警锁存和复位、运行状态反馈。我在工程里定义的电机控制FB接口如下FUNCTION_BLOCK MTR_CTRL VAR_INPUT bStartCmd : BOOL; (* 启动命令 *) bStopCmd : BOOL; (* 停止命令 *) bManualRun : BOOL; (* 手动模式直接运行 *) bFaultLevel : BOOL; (* 故障信号常闭触点断开时为TRUE *) bEStop : BOOL; (* 急停信号 *) bResetCmd : BOOL; (* 复位命令 *) END_VAR VAR_OUTPUT bRun : BOOL; (* 运行输出 *) bAlarm : BOOL; (* 报警输出 *) bReady : BOOL; (* 就绪状态 *) END_VAR VAR bRunLatch : BOOL; (* 运行保持内部变量 *) bStartPrev : BOOL; (* 启动命令上升沿检测 *) bStartEdge : BOOL; (* 启动上升沿 *) END_VARFB内部的逻辑如下(* 上升沿检测 *) bStartEdge : bStartCmd AND NOT bStartPrev; bStartPrev : bStartCmd; (* 故障和急停处理 *) IF bEStop THEN bRunLatch : FALSE; END_IF; IF bFaultLevel THEN bRunLatch : FALSE; bAlarm : TRUE; END_IF; (* 复位处理 *) IF bResetCmd THEN bAlarm : FALSE; END_IF; (* 运行控制 *) IF bStartEdge OR bManualRun THEN IF NOT bAlarm AND NOT bEStop THEN bRunLatch : TRUE; END_IF; END_IF; IF bStopCmd THEN bRunLatch : FALSE; END_IF; (* 输出赋值 *) bRun : bRunLatch; bReady : NOT bAlarm AND NOT bEStop AND NOT bRun;写这个FB时有几个细节值得展开。启动命令用了上升沿检测而不是电平触发这样做的原因是按钮信号如果长时间保持不希望电机反复重启或者持续触发启动逻辑只希望按钮按下的瞬间触发一次。上升沿检测的原理就是把当前周期的命令和上一周期的命令做与运算当前为TRUE且上一周期为FALSE时才认为出现上升沿。故障信号用了电平保持逻辑。热继电器断开一次后即使现场触点瞬间抖动恢复报警状态也会被锁存住必须手动按复位按钮才会清除。这个设计在工业现场非常重要能让操作人员明确知道设备是因为什么故障停的而不是故障一闪烁就自动恢复人还没走到设备跟前就错过了故障原因。电机运行输出在停机条件上有优先级设计。急停信号和故障信号直接强制断开运行保持停止按钮正常停机而启动条件需要满足“无报警、无急停、未运行”这三个前提。我把急停和故障检查放在前面就是为了确保它们优先级最高任何状态下都能第一时间断开运行输出。4.3 带超时报警的阀门控制FBVLV_CTRL阀门的控制和电机不同双向电磁阀有两个输出一个开阀电磁阀、一个关阀电磁阀而且还有开到位、关到位两个位置反馈。阀门控制的本质是一个位置控制过程核心是让阀门动作到目标位置并在超时未到位时产生报警。阀门控制FB的接口如下FUNCTION_BLOCK VLV_CTRL VAR_INPUT bOpenCmd : BOOL; (* 开阀命令 *) bCloseCmd : BOOL; (* 关阀命令 *) bOpenPos : BOOL; (* 开到位反馈 *) bClosePos : BOOL; (* 关到位反馈 *) bEStop : BOOL; (* 急停信号 *) tOpenTime : TIME : T#10S; (* 开阀超时时间 *) tCloseTime : TIME : T#10S; (* 关阀超时时间 *) END_VAR VAR_OUTPUT bOpenOut : BOOL; (* 开阀输出 *) bCloseOut : BOOL; (* 关阀输出 *) bOpenDone : BOOL; (* 开到位状态 *) bClosedDone : BOOL; (* 关到位状态 *) bAlarm : BOOL; (* 超时报警 *) END_VAR VAR tonOpen : TON; (* 开阀超时定时器 *) tonClose : TON; (* 关阀超时定时器 *) bAlarmLatch : BOOL; (* 报警锁存 *) END_VARFB内部逻辑如下(* 到位状态直接映射 *) bOpenDone : bOpenPos; bClosedDone : bClosePos; (* 超时定时器 *) tonOpen(IN : bOpenOut AND NOT bOpenPos, PT : tOpenTime); tonClose(IN : bCloseOut AND NOT bClosePos, PT : tCloseTime); (* 输出控制 *) IF bEStop THEN bOpenOut : FALSE; bCloseOut : FALSE; ELSIF bOpenCmd AND NOT bOpenPos THEN bOpenOut : TRUE; bCloseOut : FALSE; ELSIF bCloseCmd AND NOT bClosePos THEN bCloseOut : TRUE; bOpenOut : FALSE; ELSE bOpenOut : FALSE; bCloseOut : FALSE; END_IF; (* 报警锁存 *) IF tonOpen.Q THEN bAlarmLatch : TRUE; END_IF; IF tonClose.Q THEN bAlarmLatch : TRUE; END_IF; IF bClosePos AND bOpenPos THEN // 两个到位信号同时为TRUE视为故障 bAlarmLatch : TRUE; END_IF; bAlarm : bAlarmLatch;阀门开到位、关到位的反馈信号通常来自磁性开关磁性开关装在气缸两端。正常工作时开到位和关到位一般情况下只有一个为TRUE如果两个同时为TRUE说明传感器安装位置不对或者选型有误这种情况我直接判断为报警防止设备带病运行。超时时间的默认值我设为10秒实际项目中需要根据阀门动作速度适当调整。气缸阀门动作时间通常在0.5到2秒之间给到10秒已经是很大的余量了。如果阀门在10秒内都不到位说明大概率是气源压力不足、电磁阀卡滞或者机械结构卡死这种情况如果不在程序层面报警设备就会带故障继续运行后面引发的问题可能更严重。4.4 用CASE状态机管理设备自动流程设备和单体控制的最大区别就在于自动流程。单体控制只需要保证“接到启动就转、接到停止就停”设备级控制则需要严格按工艺步骤执行一步不到位就不能进入下一步。ST语言的CASE状态机是管理这种流程的最佳工具。以我前面说的热压设备为例自动流程设计如下步骤0待机 步骤10开阀V1等待开到位 步骤20启动电机M1延时3秒 步骤30启动电机M2同时开阀V2等待完成 步骤40加热 步骤50保压计时 步骤60停止M2、M1关阀V2、V1回到待机对应的CASE语句如下CASE g_nAutoStep OF 0: // 待机 g_bReady : TRUE; IF g_bStartBtn AND g_bModeAuto THEN g_nAutoStep : 10; END_IF; 10: // 开阀V1 vlv1.bOpenCmd : TRUE; IF vlv1.bOpenDone THEN vlv1.bOpenCmd : FALSE; g_nAutoStep : 20; END_IF; 20: // 启动电机M1 mtr1.bStartCmd : TRUE; tonStep20(IN : TRUE, PT : T#3S); IF tonStep20.Q THEN g_nAutoStep : 30; END_IF; 30: // 启动电机M2并开阀V2 mtr2.bStartCmd : TRUE; vlv2.bOpenCmd : TRUE; IF mtr2.bRun AND vlv2.bOpenDone THEN g_nAutoStep : 40; END_IF; 40: // 加热 bHeaterOut : TRUE; tonHeat(IN : TRUE, PT : T#10S); IF tonHeat.Q THEN g_nAutoStep : 50; END_IF; 50: // 保压计时 bHeaterOut : FALSE; tonHold(IN : TRUE, PT : T#20S); IF tonHold.Q THEN g_nAutoStep : 60; END_IF; 60: // 停机复位 mtr1.bStartCmd : FALSE; mtr2.bStartCmd : FALSE; vlv2.bCloseCmd : TRUE; vlv1.bCloseCmd : TRUE; IF vlv1.bClosedDone AND vlv2.bClosedDone THEN g_nAutoStep : 0; END_IF; END_CASE;用CASE写状态机有几个非常实用的经验。第一步要手动处理状态机的异常退出。设备运行过程中如果遇到急停、故障、报警不能再按照正常流程往下走需要立刻跳转到停机步骤。我通常在CASE前面加一段异常判断如果急停或者系统报警直接强制跳转到停机步骤。这一步相当于给状态机装了安全阀不会出现设备报警了流程还在往下一步拱的情况。第二部要处理好步骤进入时的初始化。每个步骤第一次进入时可能需要做一些前置操作比如清零计数器、复位延时器、初始化输出状态。我的习惯是用一个独立的步骤进入标志通过步骤号的变化检测“刚进入当前步骤”的事件在这个事件里做初始化动作。如果没有这个设计步骤逻辑里有些动作就会在每个扫描周期重复执行可能导致输出抖动。第三部是要有步骤超时保护。状态机里每一步其实都应该有一个最长执行时间超过这个时间还没满足切换条件多半是机械卡死或者传感器失灵了。在这种异常情况下如果状态机还在傻等整个设备就卡住了。步骤超时后可以做两件事要么报警停机要么跳转到专门的异常处理步骤。5. 从零搭建设备控制框架完整案例实操5.1 全局变量与IO映射在一个GX Works3工程里实际操作时我建议先建全局标签再写程序。以这个热压设备项目为例全局标签定义在标签编辑器里主要包括输入映射、输出映射、设备控制命令、流程控制标记、报警标记这几类。输入映射区在程序里长这样(* 输入信号映射 *) g_bEStop : NOT X0; // 急停按钮常闭触点 g_bModeAuto : X1; // 自动模式 g_bStartBtn : X2; // 启动按钮 g_bStopBtn : X3; // 停止按钮 g_bResetBtn : X4; // 复位按钮 g_bFaultM1 : NOT X5; // 电机M1热继电器 g_bFaultM2 : NOT X6; // 电机M2热继电器 g_bV1OpenPos : X7; // 阀门V1开到位 g_bV1ClosePos : X10; // 阀门V1关到位 g_bV2OpenPos : X11; // 阀门V2开到位 g_bV2ClosePos : X12; // 阀门V2关到位 g_bHeaterOverTemp : NOT X13; // 加热器超温保护注意急停和热继电器这类安全信号的映射用了取反操作物理信号常闭触点正常闭合时输入X0为TRUE取反后g_bEStop为FALSE表示无急停。当急停被按下X0断开变为FALSE取反后g_bEStop为TRUE表示急停状态。这样在程序里g_bEStop为TRUE就代表有急停逻辑语义清晰不会搞混。5.2 主循环程序MAINST主循环程序的职责是组织整个设备控制逻辑的执行顺序。我把主程序分为三个核心区段输入映射、设备控制、流程控制。PROGRAM MAIN VAR // 在主程序中实例化FB mtr1 : MTR_CTRL; mtr2 : MTR_CTRL; vlv1 : VLV_CTRL; vlv2 : VLV_CTRL; tonStep20 : TON; tonHeat : TON; tonHold : TON; END_VAR (* 区段1输入映射 *) g_bEStop : NOT X0; g_bModeAuto : X1; g_bStartBtn : X2; g_bStopBtn : X3; // ... 其余输入映射略 (* 区段2设备控制 *) // 电机M1控制 mtr1(bStartCmd : g_bStartM1, bStopCmd : g_bStopM1, bManualRun : g_bManualM1, bFaultLevel : g_bFaultM1, bEStop : g_bEStop, bResetCmd : g_bResetBtn); Y0 : mtr1.bRun; g_bAlarmM1 : mtr1.bAlarm; // 阀门V1控制 vlv1(bOpenCmd : g_bOpenV1, bCloseCmd : g_bCloseV1, bOpenPos : g_bV1OpenPos, bClosePos : g_bV1ClosePos, bEStop : g_bEStop); Y2 : vlv1.bOpenOut; Y3 : vlv1.bCloseOut; (* 区段3流程控制 *) // 自动流程状态机见上一节的CASE逻辑 IF g_bEStop THEN g_nAutoStep : 60; // 急停强制停机 END_IF; CASE g_nAutoStep OF // 步骤逻辑略 END_CASE; (* 区段4报警与指示输出 *) Y7 : mtr1.bRun OR mtr2.bRun; // 运行指示灯 Y10 : g_bAlarmM1 OR g_bAlarmM2 OR vlv1.bAlarm OR vlv2.bAlarm OR g_bHeaterOverTemp; // 报警灯上文代码区段的第四块里报警灯输出取了所有报警信号的或运算哪一路报警都会点亮报警灯。设备运行指示灯则是两台电机运行的或只要有电机在转运行灯就亮。这种逻辑用梯形图写起来也不复杂但放在ST里非常清晰紧凑。5.3 设备手动/自动模式切换逻辑手动和自动模式的切换是设备控制框架的核心功能之一处理不好容易出安全事故。我的设计思路是模式切换不做设备状态的实时切换而是给操作者一个“身份”在自动模式下FB收到的启动命令来自流程状态机手动按钮不会起作用在手动模式下操作者可以分别点动控制每台设备但自动流程无法启动。具体实现上模式开关X1映射为g_bModeAuto后手动/自动的逻辑分别处理(* 自动模式下流程给命令 *) g_bStartM1 : (g_bModeAuto AND g_nAutoStep 20); g_bOpenV1 : (g_bModeAuto AND g_nAutoStep 10); (* 手动模式下面板按钮直接控制 *) g_bManualM1 : (NOT g_bModeAuto AND g_bManualM1Btn);手动模式下手动按钮信号直接作为MTR_CTRL的bManualRun输入电机在无报警、无急停的情况下立刻运行。这个设计有一个安全考虑手动模式主要用于调试和检修操作者按下按钮就动作松开就停止不会有流程状态机在中间插入逻辑导致“按了没反应”的情况。还有一个细节值得注意就是自动流程在启动之前必须确认当前处于设备初始状态。状态机的第0步是待机只有在这个状态并且模式在自动、按下启动按钮时才进入流程。手动模式下无论怎么按启动按钮状态机都不会启动这样就不会出现操作者在手动模式下调完阀门切到自动模式设备突然自己跑起来的事故。5.4 通讯框架预留HMI与Modbus设备控制框架里通讯模块是现在绕不开的话题。FX3U的通讯能力在小型PLC里算比较丰富的机身上有编程口可以外扩485适配器、以太网模块。在我搭框架时通常会预留出三类通讯接口。第一类是HMI触屏通讯。现在设备基本都会配一块7寸或10寸触屏PLC和触屏之间的数据交换通过GX Works3的连接设置做好地址映射。触屏需要读写的数据在全局标签里统一规划比如设备状态、报警信息、流程步骤号、各类命令按钮。在ST框架里这些数据本来就是符号名映射起来非常方便。第二类是Modbus RTU通讯FX3U的编程口本身支持Modbus从站协议也可以扩485适配器做Modbus主站和变频器、温控表、智能仪表通讯。做设备框架时我一般把Modbus通讯的逻辑独立成一个程序块和主控制逻辑分开。这样主程序负责设备控制通讯程序块负责数据交换彼此不干扰。第三类是上位机数据采集通过以太网模块或串口转以太网网关把设备运行状态、产量数据、报警记录定时上传到上位系统。在FX3U上做这类通讯一般用三菱的MC协议GX Works3里配置好网络参数后上位机可以直接读写PLC的软元件。我在框架里单独开辟一块数据区专门存放给上位机读的数据这块数据区用字和位混合编排字段含义在注释里标注清楚。这样上位机工程师对接时不看你整个程序的逻辑只看这块数据区的定义就够了能省去大量联调时来回沟通的时间。6. 调试实录与常见问题排查6.1 编译与下载阶段的坑ST编程和梯形图一样写完程序要经过编译检查才能下载到PLC。FX3U在GX Works3里编译ST程序时碰到最多的问题是变量声明和数据类型不匹配。我遇到过几次很典型的编译错误。第一次是VAR_INPUT里声明了一个BOOL变量但在调用FB时传进去的是一个INT变量编译直接报类型不匹配。ST语言是强类型语言BOOL就是BOOLINT就是INT类型对不上就不让过。这种问题在梯形图里几乎不存在但在ST里必须养成类型匹配的习惯。第二个常见编译问题是未声明的变量。ST里每个变量都要先声明后使用在程序体里写了一个标签编译器不认那一定是在全局标签或者局部声明里漏掉了。GX Works3的智能提示功能可以做标签补全写得多了基本不会犯这种错。下载程序时要注意FX3U下载ST程序需要PLC处于STOP状态。在线修改程序必须谨慎特别是修改FB的接口定义或者变量声明时可能导致PLC报参数错误甚至程序丢失。我的原则是改动较大的情况下先停机、再下载、再RUN不在设备运行中去试险。设备运行中只想修改某个流程参数时尽量通过HMI的配方功能来实现不做在线程序变更。6.2 运行期逻辑问题排查程序下载到PLC里运行最常见的故障是设备动作不正常或者报警误报。我的排查思路是自底向上逐级排查先在设备控制区看FB实例的输入输出状态再向上看流程控制区。FB实例的状态在GX Works3的监控窗口里可以直接查看包括VAR_INPUT、VAR_OUTPUT、VAR内部的局部变量都能实时显示。一次排查电机不启动的问题时我打开监控发现MTR_CTRL实例的bAlarm输出是TRUE说明FB内部触发了报警锁存。再看bFaultLevel输入是TRUE说明现场热继电器反馈信号异常。顺藤摸瓜查下去发现是热继电器接线端子松了信号时通时断。FB把这种瞬时抖动锁存成报警反向帮我们定位了症状根源。用ST排查逻辑时有个梯形图没有的便利加了注释的代码本身就是排查文档。我在每个FB实例旁边都写了中文注释标明这个实例控制的是哪个设备、对应哪个接触器、反馈点在哪个位置上。设备出问题时打开程序顺着注释看一遍比对着图纸翻梯形图快得多。6.3 定时器和状态机的边界情况处理ST编程中定时器的边界情况经常被忽视。TON定时器在IN输入持续为FALSE时当前时间会清零Q输出为FALSE。这个特性在状态机里要特别注意如果步骤切换时定时器没有复位下一次进入该步骤时定时器的当前时间不是从零开始计数会导致步骤提前切换。我在状态机里用定时器时有一个固定习惯每个定时器只在对应的步骤号下才允许IN为TRUE步骤切换后IN自动变FALSE定时器自动复位。写法和上文的CASE代码一样定时器IN写的是步骤条件而不是单纯的TRUE常量。如果某一串流程需要独立计时我会单独定义专用的定时器避免和其他步骤共用防止定时器状态串扰。状态机的步骤号还有一个容易踩的坑FX3U的INT类型在监控中显示为带符号整数步骤号如果超过32767会溢出。实际设备流程不可能跑这么多步但以防计算逻辑里出现负数步骤我在CASE之前加了步骤号的范围保护一旦发现步骤号不在合法范围内强制跳转到待机状态。这个保护逻辑用ST写一行就够用梯形图写要好几行ST的优势在这里体现得淋漓尽致。6.4 常见问题速查表现象可能原因排查方法编译报错类型不匹配变量声明类型与赋值不一致检查VAR_INPUT和实际传入参数的类型FB实例无输出FB未在程序中被扫描到确认FB实例在MAIN程序中被调用电机启动后立刻停止热继电器反馈异常或急停信号误触发监控bFaultLevel和bEStop输入阀门开阀后无到位信号磁性开关位置偏移或线路断开检查到位信号输入指示灯自动流程停在某一步不切换步骤切换条件未满足监控步骤号对应的切换条件状态机乱跳步骤号越界或定时器未复位检查CASE前有无异常保护跳转6.5 现场经验补充接线与抗干扰程序写得再好现场接线不配合也会出幺蛾子。ST框架设计得再精密抗干扰能力不够还是白搭。我在项目里总结的几条现场经验分享给大家。第一PLC输入端的COM端接线必须规范。三菱FX3U的输入是漏型输入传感器的NPN输出要接到对应的X点公共端接24V电源正极。现场传感器类型接错轻则信号不动作重则烧毁输入点。ST程序做得再好物理信号进来就是反的或者没有信号框架也救不了你。第二动力线和信号线要分开走线。变频器、接触器、电机的动力电缆会产生比较强的电磁干扰如果和传感器的信号线捆在一起走干扰信号就可能串进PLC的输入端导致误动作。这套设备框架里的报警锁存逻辑能防住一部分瞬时干扰但根本解决还要靠物理层面的抗干扰措施。信号线用屏蔽线屏蔽层单端接地这些细节省不得。第三急停回路必须用硬接线不能只靠PLC程序。急停按钮的常闭触点应该串联在接触器控制回路里直接切断动力电源PLC程序里的急停处理只是第二道保护。我搭建的ST框架里急停信号在程序里做了很完善的联锁处理但硬接线的安全回路始终是底线。PLC死机了、程序跑飞了、输出模块烧了硬接线回路依然能保护设备和人员安全。做设备控制框架永远要记得程序只是控制的一部分不是安全的全部分。结尾一点个人经验这套基于FX3U的ST控制框架我从一个几十点的单机项目开始写起前前后后在实验室和小型设备上折腾了两个月才稳定下来。回过头看最大的收获不是学会了ST语法而是理解了框架的价值——好的程序结构能让设备出问题时十分钟定位故障糟糕的程序结构能让一个简单的停机问题查到半夜。最后给大家两个小建议。第一个建议是FB内部逻辑尽量设计得通用避免把设备和流程相关的特殊逻辑写进FB里。电机FB就老老实实做电机控制阀门FB就做阀门控制设备和流程相关的逻辑放在外面的状态机里。这样FB才能在不同项目之间反复复用你花在FB上的时间才能真正变成自己的积累。第二个建议是写ST程序时多写中文注释特别是FB实例和状态机步骤的注释。三五年后你再打开这个程序会感谢当年注释写得清楚的自己。如果你正准备在FX3U上搭建自己的设备控制框架或者正纠结要不要从梯形图转向ST我的看法是直接干值得的。从第一个FB跑通开始你就会慢慢体会到结构化编程带来的掌控感——程序越写越清晰设备控制越来越有信心这才是干设备控制这行最踏实的底气。
返回列表