PLC程序能运行不等于写得好:六个维度提升程序质量
“PLC 程序能运行就算写得好吗”这个问题我在调试现场被问过很多次也问过自己很多次。刚入行那会儿我觉得程序能跑、设备能动、信号能通项目就算交付了。后来带项目、做维护、接手别人写的程序才慢慢意识到“能运行”只是底线离“写得好”还有很长一段路。这篇内容我想结合自己做过的项目聊聊我对PLC程序质量的理解以及从“能跑”到“好维护、好扩展、好交接”到底差在哪儿。1. 能运行是底线写得好是另一回事1.1 先搞清楚“能运行”意味着什么一个PLC程序能运行通常指的是逻辑没有致命错误输入输出能正常反应设备按预想动作没有频繁死机或误动作。说白了就是设备能转起来、生产能继续。这是所有PLC程序的及格线也是甲方验收的基本条件。但“能运行”掩盖了大量隐患。我见过一个项目某厂一条包装线的程序已经稳定运行了大半年操作工也觉得挺好。结果有一天更换传感器型号维护人员打开程序一看发现所有的输入信号都写在没有注释的地址里程序段之间没有分割线内部继电器用的是默认编号连变量表都是空的。想改一个光电信号找了两个小时没找到对应的点最后只能在线监控一个个点去试。这种程序能运行谁敢说它写得好我在实际项目中总结过一句大实话“能运行”是写给设备看的“写得好”是写给下一个工程师看的。1.2 为什么“能运行”的标准远远不够PLC程序的特殊性在于它和普通PC软件不一样。PLC运行在工业现场生命周期通常是五年、十年甚至更久。设备装上去以后很少直接报废更多是改造、升级、换传感器、改工艺参数。这就意味着你的程序不只是给设备用的更是给未来接手的人用的。一台设备的程序真正运行的时间只占它生命周期的一小部分。更多的时间里它在被人阅读、修改、排查、调试。一个质量差的程序可能在运行期间看不出问题但只要一次改造、一次故障排查就会把维护成本无限放大。我参与过一个跨平台系统的模拟改造项目甲方原来的程序是一个老工程师写的。程序全部堆在一个OB1里足足有三千多行没有子程序没有函数块也没有任何注释。我们接手时光是理解原有逻辑就花了两周。设备本身没什么技术难度难的是从那堆“能运行”的代码里把工艺逻辑提取出来。这个项目的成本一大半浪费在读旧程序上而不是写新程序。所以我一直跟团队说能运行只是起点好维护才是关键。2. 判断PLC程序质量的六个维度2.1 可读性别人能不能看懂你的程序可读性是最直观的维度。一个程序好不好不需要看运行效果单看代码就能知道个大概。我判断可读性有三个标准是否有完整的变量表每个变量有名字、有注释、有地址规划程序段是否有逻辑分组段与段之间的边界清晰关键逻辑是否有注释说明“为什么这么做”而不只是“做了什么”举个例子两个工程师写同一个电机启停逻辑。一个写得干干净净#电机启动按钮 触发后置位 #运行模式另一个写得能跑但乱七八糟A I0.0 AN I0.1 Q0.0第二个程序现场改起来就只能靠猜费时费力。可读性差的程序是维护工作的第一号敌人。2.2 可维护性改一个功能要动多少地方维护性差最常见的表现就是改一个功能要牵连好几个地方。我见过一个程序控制一个气缸的动作相关逻辑分散在五个网络里中间变量用了三四个不同的编号想调一个延时参数要翻遍整个程序才能找到所有相关位置。好的程序通常把一个功能封装成功能块所有的输入输出都通过接口传递。改参数只需要在调用接口处调整不用满程序找点位。可维护性的核心指标就是改动一个功能是否只需要动一个地方。2.3 结构性程序是搭积木还是缝包袱结构化编程的思路是把复杂工艺拆成相对独立的模块。比如一条生产线可以分成主控逻辑、执行机构控制、报警管理、手动模式、自动模式、与上位机通讯。每个模块相对独立接口清晰。结构差的程序有一个显著特征整段代码线性堆叠从头到尾一条主线走到底。这种程序在简单设备上勉强能用设备复杂以后就别提了全靠逻辑跳转和置位复位操作硬撑最后连写程序的人都会迷路。我是踩过这个坑的。有一回独立做一台小型组装机的程序单按钮启停、气缸顺序动作、报警复位逻辑不复杂我就没做模块划分全部写在一个OB里。刚开始调试没问题后来甲方加了两个功能需求一个手动单步操作一套产量统计我改起来就开始混乱了。加上之前的逻辑有交叉改一个地方另一个功能莫名其妙就不动了。最后花了足足双倍时间才把逻辑理清楚。2.4 复用性换个设备还能不能用质量好的程序模块应该具备可移植性。我做标准设备的时候就想着一台机器的程序写好了下一台同型号的机器应该能快速复制、快速调整而不是从头再写一遍。要提高复用性就得把共同的功能提取成功能块。比如气缸控制、电机控制、模拟量滤波、报警处理、节拍统计都属于高度通用的模块。把它们封装好单独验证过以后做新项目直接调用底层的正确性是有保障的只需要关心工艺参数。2.5 健壮性出了异常程序怎么表现能运行的程序在正常工况下可能表现良好但好程序要经得起异常情况的考验。比如气缸到位信号一直没触发怎么办、通讯断开了怎么办、压力传感器读数超限怎么办。健壮性体现在程序的“兜底能力”上。好的程序会为每个动作设置超时保护信号出现异常会报警停机不会盲目往下执行。一些粗放的程序依赖操作工的经验去预判出错实际上是非常危险的。调试时我曾看到一个程序气缸动作后没有任何到位确认全靠延时硬等结果机械卡住后气缸继续动作故障的根源就在于程序缺少闭环反馈检查。2.6 性能扫描周期和资源占用这是很多人忽略的维度。PLC的扫描周期直接影响设备的响应速度。一个逻辑写得环环相扣、嵌套很深的程序计算量成倍增加扫描周期拉长以后高速信号的采集精度就会急剧下降。我测过一个程序某个项目里的一段模拟量滤波放在全局执行每次扫描都做几十次浮点计算导致整体扫描周期从5毫秒涨到了15毫秒。后来改成只在数值变化时触发计算扫描周期立刻降回正常水平。性能优化的关键是不该在全局循环里做的事就不要放在全局循环里。3. 从“能运行”到“写得好”的实操改进路线3.1 先把命名规范和变量规划做好很多新人写程序不重视变量命名觉得缩写省事点表乱一点无所谓。但恰恰是这一步决定了整个程序的地基。我经手过的项目中凡是后期维护顺手的无一例外变量表都清清楚楚。关于命名我有几条心得I/O点用统一的规则命名比如“M1电机运行反馈”“M1电机启动命令”一看就知道描述的对象和类型中间变量不要用D0、D100这样的默认编号裸奔给每个变量起个有业务含义的名字功能块FB的接口命名要完整输入端、输出端、静态变量区分清楚常量比如延时时间、报警阈值单独规划区域集中管理拿一个简单的例子说明一个气缸控制变量表如果写成“Y1”“X2”“T37”别人看三天都看不出逻辑但如果写成“气缸A伸出到位”“气缸A缩回到位”“气缸A伸出电磁阀”任何人打开程序不等看完注释就知道这段逻辑在干嘛。3.2 注释怎么写的实操心得很多人不是不想写注释是不会写、没养成习惯。我写注释的原则是注释解释“为什么”和“注意什么”而不是复述“做了什么”。对比一下两种注释差// Q0.0 置位这句话说了等于没说代码本身已经是这个意思好// 停止条件触发后延时2秒再断输出防止气缸惯性冲出好的注释会告诉你——这是一个传感器换了型号以后才加的逻辑没有它设备会误动作这个延时值从哪来等等。这些背景信息是代码读不出来的只能靠注释带出来。还有一个实操技巧凡是你在调试时踩过的坑都可以作为注释素材留在对应的程序段里。比如你在某个位置加了一个互锁条件因为之前出现过两个气缸同时伸出撞车的事故这个背景是非常关键的注释信息一定要写下来。以后不管是你自己回查还是别的工程师维护看到注释就知道这个互锁不能乱删。3.3 用状态机替代散装逻辑工艺控制逻辑越复杂越需要状态机思维。简单说就是把设备的运行状态划分为有限的几个状态任何时候程序只处于其中一个状态状态切换有明确的触发条件。我调试交通灯模拟Demo时用过这个思路。程序把信号周期分为以下状态初始化、东西通行、东西绿灯闪、东西黄灯、南北通行、南北绿灯闪、南北黄灯。每一个状态内只处理对应方向的控制状态切换条件写清楚。整个程序的结构非常清晰新增一个行人专用相位也只需加一个状态改动局部不伤全局。对比一下散装逻辑如果用一堆定时器加置位复位操作去实现交通灯每一个灯柱的启停逻辑都分散在不同的网络里改动一个时间参数要牵连好几个段落状态一多必乱。3.4 把通用功能封装成功能块这是我强烈建议早一点掌握的习惯。功能块FB/FC就是PLC里的“函数”把某个功能封装成独立模块通过输入输出参数与外部交互。那些与具体设备无关的通用功能非常适合做成功能块沉淀下来。举一个我常用的模拟量滤波功能块输入端原始模拟量数值、滤波器系数输出端滤波后数值、变化率、超限报警内部逻辑一阶惯性滤波算法 限幅检测这个功能块我在不同项目里用了很多次只需要调整滤波器系数和量程范围适用于温度、压力、流量等各种模拟量信号。每用一次验证成本就降低一分可靠性却越来越高。封装功能块的好处不仅在于复用还在于可测试性。单独验证一个功能块比在一整段程序里找问题要轻松得多。调设备的时候能快速确定问题出在模块内部还是模块之间的配合上。3.5 分周期、分任务处理不同类型逻辑程序量大以后把不同类型的逻辑放到不同的任务里执行是一种高效策略。我习惯这样划分全局级别的逻辑系统急停、运行模式切换、报警汇总放在主任务里执行机构级别的逻辑气缸、电机、阀岛控制放在各自的功能块里由主任务调用高速响应逻辑编码器计数、高速计数中断放在中断任务里数据采集和记录模拟量采集、配方管理放在慢周期任务里举例来说模拟量采集不需要每个扫描周期都做放在100毫秒的循环任务里急停逻辑需要毫秒级响应就必须在主任务最前面。这种划分比把所有逻辑都堆在一个大循环里要科学得多。4. 常见“能运行”陷阱与排查心得4.1 只用一个常开触点调试点的问题新手调试时有一个通病把所有需要临时跳过或强制置位的逻辑用一个公共触点挂在程序段前面调试完也不删。这个习惯很危险一次调试设备正常了但公共触点一直开着现场有其他人改成常闭、误动整台设备就跟着乱。我的实操经验是调试用的临时触点务必加一个醒目的前缀比如“临时调试_xxx”每个项目收尾时逐一确认全部移除或者改成正式逻辑。4.2 通讯程序的超时保护缺失与变频器、仪表、触摸屏做通讯时程序出现通讯断线的情况非常常见。能运行的程序通讯正常时可能一直很稳定通讯异常一来没有超时保护的话程序就会用旧数据继续计算输出会偏离真实工况非常容易引发设备误动作。处理方案并不复杂每个通讯周期记录上一次通讯成功的时间间隔超过设定值即可认为通讯超时。超时后要做什么取决于设备特性——有的要立刻停机有的要输出保持、但给出报警。这里还有一个细节通讯超时判断和报警复位逻辑要特别处理好复位命令避免通讯恢复后设备不明原因地重新动作。4.3 数据块里的“礼貌性复位”我在一个项目里遇到过这种情况HMI上按下复位按钮后设备恢复正常但生产中途偶尔出现料位显示成负数或者位置莫名其妙跳变。查了很久才发现问题出在复位逻辑里用了一条数据块整体清零指令把正在使用的通讯数据、配方数据、累计产量全部清掉了。这种情况尤其容易出现在使用数据块DB存储中间状态的程序里。复位逻辑的本意只是清报警标志数据块整体清零用起来简单实际却很危险。我后来在团队里定了条规矩复位、初始化逻辑只对必要的变量操作区域清零指令除非特殊场景整机复位出厂否则谨慎使用。4.4 扫描周期和数据一致性能运行的程序容易出现“数据读取不一致”的隐患。比如在一个扫描周期里某个压力传感器的值要被多处引用现场调试时发现两个不同的程序段读到的数值不同——因为传感器值在扫描周期中途被数据块更新了。解决方案是关键数据统一在读输入阶段采集一次存到固定的中间变量里后续逻辑统一引用这个中间变量保证全周期内数据的一致性。在我经手的图像处理Demo控制项目中视觉检测的结果信号处理也有类似问题。相机输出的检测值如果在程序的多个网络里各自读取就可能出现互相矛盾的状态。后来把所有检测区域的输出统一映射到某一个数据块中再供后续控制逻辑统一调用问题彻底消失。可以形成的速查表典型问题识别方法补救措施无注释、无变量表打开程序一片空白没有可读信息补全变量表和段说明重点逻辑加注释功能逻辑分散改一个功能要搜索多个网络提炼功能块逻辑收敛临时触点残留程序段前有标记为“调试”的常开/常闭点未删逐个移除或改成正式逻辑通讯超时无保护通讯异常后程序继续用旧数据运行增加超时监控和状态切换复位移除关键数据复位后产量、配方数据被清零复位逻辑只清报警与临时标志数据不一致同一次扫描中多处引用同一信号结果不一致输入阶段统一采集统一引用扫描周期过长在线监控显示周期波动异常检查全局循环中的重计算与延时逻辑5. 团队协作里的代码评审和版本管理5.1 代码评审看什么我们团队内部做过的代码评审前期往往是问题最密集的时候。如果只靠各自埋头写、现场调试时再磨合很容易出现设备动作没问题但维护难度极高的情况。后来我们把代码评审作为常规流程评审前先交代工艺背景和关键约束避免评审人只看代码不看场景评审重点放在接口设计、状态切换、异常处理、注释解释这四类问题上命名、格式、变量表的规范也单独过一遍虽然不涉及核心逻辑但对后期维护影响很大评审的目的不是找谁的错而是把所有容易在设备上暴露的问题前置。有一次我在评审时发现一个功能块里把常开互锁和常闭互锁接反了信号翻转导致整条动作链在异常状态下会变成相反的行为这种问题在现场可能要排查一整天在评审环节几秒钟就能抓住。5.2 不同版本的比较和维护PLC程序在调试和投产后经常连续修改。没有版本管理意识的话程序就会变成“最终版”和“最终版2”并存谁也说不清现场跑的到底是哪一个。更糟的是改过的程序没记录改了什么、为何要改几个月后回查很难定位。我现在常用的做法是修改前保留一个原版本存档修改完成后注明修改日期和内容说明关键的工艺参数调整建立参数对照表设备在客户现场时程序文件与现场版本始终保持一致性版本管理的核心思路不在于工具多高级而在于记录和一致性。一个人维护时可能感觉不到多人协作时这就是纪律问题。5.3 提升程序质量的多条学习路径其实大家真正关心的是我现在程序还比较初级怎么提升自己我的建议是先对着自己以前写的程序做一次“翻新”。把变量表补全、把散落的逻辑封装、给关键段落加上注释这个过程比新写一个程序更能提升水平。做完之后你会清楚地看到哪些设计决策当初影响了现在的维护难度。然后读别人写的优秀程序尤其是大品牌设备里自带的示例库注意它们的数据组织方式、接口定义方式、模块化思路。看到好的结构就把它用到自己的下一个项目里。还有一个不花钱的方法把自己的程序复述给同行听。你如果能用普通语言把程序的架构、状态切换逻辑、每段代码“为什么在”讲清楚那就说明你自己真正理解了。讲不清楚的地方大概率就是需要改进的地方。6. 写在最后的几个小建议程序能不能运行标准是设备程序写得好不好标准是人。设备只能验证程序的正确性人才能判断程序的可维护性和扩展性。我自己的体会是把每一次编写程序都当作给未来接手的人准备一份说明书这会从源头改变你写程序的方式。你会更愿意花时间做规划、写注释、理状态而不是急着往程序里塞逻辑。如果你刚接触PLC编程可以把“程序能运行”当成第一关把“三个月后我自己还能看懂”当成第二关把“换了工程师他也能快速上手”当成第三关。大多数人卡在第二关。过了这一关你就再也不是那个只会让设备点头的工程师了。最后分享一个我保留了很多年的习惯每次项目收尾我都会把程序从头到尾读一遍顺带把自己在调试时临时加进去的“小补丁”清理干净。这个动作不需要多少时间但每一次都能发现可以优化的细节。少一点补丁、多一点设计程序的质量就是这么一点一点积累出来的。