☰
PLC程序能运行不等于写得好:从能跑到好写的四个核心标准
2026/10/12 2:59:18 网站建设 项目流程

写PLC程序这份工作,最容易被误解的一个词就是"能运行"。我见过太多设备程序,调试的时候一切正常,产量达标、班产满负荷,可真正的问题往往在三个月甚至半年后才暴露——维修工凌晨三点打来电话说设备莫名其妙的停机,打开程序一看,几百行没有注释的梯形图堆放在同一个扫描周期里,变量名全是A1、X7这种"暗号",谁也不愿意接手去查。所以在PLC这个行当里,"程序能运行"和"程序写得好"之间,隔着一条很深的沟。这条沟平时的损失看不出来,但一旦遇到设备改造、故障排查、产能提升,就会立刻变成钱和时间的黑洞。

"能运行"不过是入场券,是程序员最基本的下限;而"写得好"要求的是可读性、可维护性、可诊断性和安全冗余这套完整的上限。这个道理,我是踩过不少坑、帮别人收拾过不少烂摊子之后才真正搞明白的。这篇文章我就掏心窝子聊聊,到底什么样的PLC程序才算写得好,以及从"能跑"到"好写",中间到底差了哪些东西。

1. 从"能运行"到"写得好",问题到底出在哪

1.1 能运行只是入场券,不是成绩单

先说个扎心的事实:PLC程序能跑起来,只能说明你的逻辑没有重大的语法错误,输入输出映射得也对,设备能按照基本时序动作。但这是PLC编程的门槛,不是目标。就好比一个人会写字,不代表他写得出好文章;程序"能动",只说明它是一段能执行的代码,不代表它经得起停机、改造和维护的考验。

我在现场见过最典型的例子是一个老设备,程序全部塞在一个OB1块里,逻辑大概有三千多行,跨越了十几个网络。设备本身就是一个中等复杂度的自动化单元,涉及六个气缸、两台变频器、一个称重模块。它天天在跑,产线也没停过,看起来岁月静好。但有一次车间要增加一个扫码枪,只是想在输送链的某个位置加一个信号判断,工程师打开程序从头翻到尾,愣是花了整整两天才定位到需要改动的那几个网络,最后改完还提心吊胆,生怕漏掉哪个跳转逻辑没同步改。这种程序,你说它"能运行"吗?当然能。但你说它"写得好"吗?显然不合格。

"能运行"和"写得好"的本质区别在于:前者只要求程序在当前条件下输出正确动作,后者要求程序在未来的各种变化下依然安全、可维护、可扩展。如果你的程序只满足当前工况,那每一次方案修改都是一次冒险。

1.2 三个典型"能跑但不敢碰"的现场

我整理了几个现场最常见、也最让人头疼的情况,大家可以对号入座。

第一种是"面条式"逻辑。程序没有模块划分,一个组织块里什么都有,伺服、气缸、报警、真空、统计掺杂在一起,跳转指令满天飞。这种程序最大的问题是牵一发而动全身——你永远不知道某个线圈在哪几个地方被输出,改了一个地方,可能另一个地方就冲突了。

第二种是"暗号式"命名。变量叫M0.1、M100.3,或者是A1、B2,没有前缀,没有注释,没有数据块结构。写程序的人自己可能记得,三个月之后他也忘了。这种程序一旦交接,接手的工程师基本只能靠猜。

第三种是"裸奔式"的故障处理。程序里没有任何故障诊断、没有报警分组、没有安全联锁的冗余逻辑。设备一出问题,没有任何提示,操作工只能干瞪眼,维修工来了也只能用万用表从头到尾钳信号,靠"逐点排查"来碰运气。

这三种情况对应的程序,全都"能运行",而且可能运行了好几年。但它们没有一种称得上"好"。因为程序的真正使用寿命不是调试完那几天,而是在产线上持续服役的整个生命周期。

1.3 好的标准在不同人眼里完全不同

说句实话,不同角色对"写得好"的理解差距非常大,这也会影响你对程序质量的判断。

老板眼里,"好"就是设备稳定、别停机、别再花钱改来改去。操作工眼里,"好"就是报警信息清楚、复位简单、操作界面友好,别半夜三更不知道怎么处理。维修工眼里,"好"就是故障能快速定位、模块能单独测试、程序结构一眼能看懂。而作为编程工程师,你的责任是同时满足这三类需求,而不只是让程序在你的电脑里"仿真能跑"就交差。

我遇到过不少工程师把"仿真能跑"当成"程序合格"来交付。仿真通过意味着逻辑是对的,但它验证不了现场的真实情况:通信中断、传感器信号抖动、气缸行程不到位、急停在不同时序下的响应。这些问题,只有程序结构足够好、诊断足够完善,才有办法快速暴露和解决。否则,仿真过了、现场一上电,你就等着被车间电话轰炸吧。

2. 评判PLC程序质量的四个核心维度

2.1 可读性:程序不是写给自己看的

可读性绝对是第一位的。很多人觉得,我写的程序我自己能看懂就行,别人看那是他们的事。这话大错特错。设备五年之内大概率会改造,你也许会升职,也许会换项目,总有一天别人要读你的程序。就算你一直管着这段程序,三个月之后你再回来看自己写的一坨逻辑,照样会头痛。

怎么提升可读性?至少要做到三件事:结构清晰、命名规范、注释有效。

结构清晰,就是按功能把程序拆成不同的模块块。比如把报警逻辑统一放在一个功能块里,把气缸控制统一封装成独立的FB,把配方管理单独建数据块。命名规范,就是变量名要能"见名知意"。注释有效,不是写"启动电机"这种废话,而是写"为什么这里要延迟2秒才启动电机——因为需要等待润滑泵建立压力"这种真正有价值的信息。

我自己的习惯是,给每个功能块写块头注释,标注清楚作者、日期、版本、功能描述;给每个关键动作写逻辑说明,尤其是那些加了延时、锁存、复位的网络,一定说明设计意图。这些注释在调试和后期维护中救过我很多次命。

2.2 可维护性:程序是要"养"的,不是一次性消耗品

可维护性说白了就是程序好不好改。好的程序改一个功能只需要动局部,坏的程序改一个功能需要排查全局。

模块化和封装是提升可维护性的核心手段。比如你要控制二十个气缸,没有封装的情况下你可能会写二十份差不多的梯形图逻辑,每个气缸都有一套差不多的动作判断和输出。等需要改一个公共逻辑——比如每个气缸都要加一个到位超时报警——你就得改二十处。而如果你把气缸控制封装成一个功能块,输入是"请求伸出""请求缩回""到位反馈""超时时间",输出是"伸出输出""缩回输出""故障标志",那么改超时逻辑只需要在功能块内部改一处,二十个气缸全部生效。

这种设计思路跟软件行业说的"复用"是一个道理。PLC程序虽然跑在工业设备上,但代码工程化的思想完全适用。

还有一点:尽量少用M中间继电器绕来绕去的写法。M变量在PLC里是全局的,没有任何封装和所有权概念,谁都可以写,谁都可以读,程序一复杂,冲突排查起来极其痛苦。我的建议是,凡是不能一眼看出归属的中间逻辑,都应该定义为某个功能块的接口变量或者某个数据块元素,让它有明确的"所属"和"用途"。

2.3 可靠性:故障处理才见真功夫

写一个正常情况下跑得顺的程序不难,难的是写一个出了任何状况都能安全停车、并且能告诉你问题出在哪的程序。

PLC项目最大的特点就是它面对的是实打实的物理世界。传感器会坏,通讯会断,气缸会卡,气源压力会掉,操作工会误操作。程序如果没有对这些异常情况做逻辑兜底,那设备迟早会在你最不希望的时候出乱子。

可靠性要分软件和硬件两个层面讲。硬件层面,急停回路、安全门、光栅这些必须通过硬接线接到安全继电器和接触器上,绝不能只靠PLC程序去切断动力。这是底线,不容讨论。软件层面,你要做的是一套完整的状态监测和联锁逻辑:气缸动作超过设定时间还没有到位,必须报警并且切断后续动作;配方参数超出允许范围,必须拒绝执行并提示;通信超时,输出应该进入一个预设的安全状态,而不是保持最后一次的数值。

这部分内容做得好不好,直接决定了设备的综合效率。很多设备三天两头停,不是因为"大毛病",就是因为报警信息不明确、联锁不完善,小故障被拖成了大故障。

2.4 可扩展性:给未来的自己留条后路

产品工艺一定会变,产能一定会提升,设备一定会增加新的工位和传感器。程序如果写死了,每次改造几乎等于重写。

可扩展性要求你在设计结构的时候,就把"变化"当成理所当然。比如设备有十个配方,你就不要只建一个配方数组大小为5,哪怕当前只用3个,也要留足余量。新增一个传感器信号,你应该能通过改硬件组态和关联变量来完成,而不是去给所有逻辑加网络。

还有一点就是不要滥用全局变量去连接不同模块的逻辑。模块之间的通信尽量通过接口和数据结构完成。比如一个工位模块执行完,通过一个明确的"完成"信号告诉下一个模块,而不是让两个模块直接操作同一个中间线圈。这样以后增删模块时,就不会互相影响。

3. 同一台设备,两种写法差距有多大

3.1 场景:一个简单的搬运工位

为了让上面说的东西更直观,我拿一个最简单的工位来举例。假设有一个上下料工位,动作流程是:

  1. 启动按钮按下。
  2. 夹爪气缸伸出,夹取工件。
  3. 夹紧气缸动作。
  4. 垂直气缸上升,把工件提到安全高度。
  5. 水平气缸移动,把工件送到下一工位。
  6. 各气缸按顺序退回。

就这么个流程,同时需要检测气源压力、急停状态和每个气缸的到位信号。

3.2 反面写法:全堆在主体扫描逻辑里

很多人会这样写:在主体程序里复制六段网络,第一段输出夹爪伸出,等它的到位信号到了,第二段才输出夹紧;夹紧到位了,第三段输出上升……以此类推。每个气缸有两三个网络,再加上启动条件、互锁条件、延时,一个工位下来几十个网络,全部塞在同一个块里。

这种写法表面上顺序清晰,实际上隐患非常明显。第一,互相之间的启动和停止条件容易重叠,改一个网络要小心别把另一个条件给删了。第二,没有任何复位逻辑,任何一步不到位,整个顺序卡死,操作工除了断电重启没有别的办法。第三,气缸卡死、超时无报警,只有等操作工发现"设备不动了"才会去排查。第四,如果后续设备要多加一个工位,整套逻辑你差不多还得再复制一遍,代码量哗哗涨。

3.3 正面写法:状态机方式实现

把同样的逻辑用状态机来写。先定义一个状态字,0表示空闲,10表示伸出夹爪,20表示夹紧,30表示上升到位,40表示横移到位,50表示横移退回,60表示下降退回,90表示故障。

主体程序不再是一长串顺序指令,而是按状态来跳转:当状态为0且启动条件满足时,输出夹爪伸出,并将状态切到10;当状态为10且伸到位信号为真时,输出夹紧,切到20;如果是故障状态,则根据复位按钮决定是否退回到0。

这种写法的好处非常明显:程序的逻辑结构跟人的思维习惯对应,一个扫描周期内就能看到设备当前处于哪个状态;出现任何异常,状态停在某一步,维修工一眼就知道卡在哪个动作;要增加一个中间工位,只需要增加一个状态值和一个判断网络,其他逻辑完全不用动。

而且状态机便于嵌套报警逻辑:状态不为0且某个超时计数器到达设定值,立刻把状态置为故障,并把故障代码写到报警字里。这样上位机屏幕上就能直接显示"夹爪伸出超时"还是"上升不到位",排查时间从小时级降到分钟级。

3.4 两种写法的对比表

对比项目反面写法(堆叠逻辑)正面写法(状态机)
可读性逻辑分散,看懂需从头顺到尾状态一目了然,看状态就知道卡在哪
可维护性增一个动作要改多处网络增一个动作只需加一个状态和一个判断
故障诊断无任何诊断,只能靠人猜超时自动报警并记录故障状态
复位处理无统一复位,只能断电重启一键复位,自动回到空闲状态
扩展性新增工位几乎要复制整套逻辑新增工位增加独立功能块实例
后期维护维修工不敢碰普通的设备维修人员也能快速上手

这个表格不是我拍脑袋想的,是我用两个实际项目观察到的差距。那些用了状态机、模块化结构的程序,后期改造的响应速度明显快得多;而那些堆逻辑的程序,每改动一次都像是在解绳结,越解越乱。

4. 把程序从"能跑"变"好写"的具体方法

4.1 变量命名:先立规矩再写代码

命名这事看着不起眼,实际决定了一个程序的上限。我建议至少遵循这几条:

一是前缀要能表达数据类型和逻辑含义。比如数字量输入用DI前缀、数字量输出用DQ、模拟量输入用AI、内部位变量用BIT、定时器用TON、计数器用CT。这样看到变量名,不用查区块就知道它是什么类型、从哪里来。

二是名字要见名知意。不要用A1、X7,要用"气缸1伸出到位""真空检测无料""传送带启动请求"这种能直接读懂的命名。变量名长一点没关系,PLC的内存根本不在乎这几个字节,关键是要让读程序的人节省时间去猜。

三是属于某个功能块的局部变量,尽量定义在功能块接口里,而不是用全局M变量。这样数据边界清晰,别人调用你的功能块时,只需要关注接口说明,不需要关心内部实现。

四是要有统一的地址映射表。设备上每个传感器、每个执行器对应哪个PLC输入输出点,应该有一份清晰的表格,最好在条件允许时跟电气图纸一一对应。这份表是程序维护的"地图",没有它,排查故障的效率至少掉一半。

4.2 程序结构:分层、模块化、接口清晰

PLC程序的结构,我推荐按照"主循环—功能块—设备封装"三个层次去组织。主循环只做调度和系统级联锁,不写具体的设备动作逻辑;每个工位或者每个功能单元,对应一个独立的功能块;在功能块内部,再细分状态控制、报警处理、操作模式切换等逻辑。

举个例子,一个完整的设备可能有"上料工位""加工工位""下料工位"三个功能单元。我每个工位写一个功能块,这些功能块的接口无非就是启动请求、停止请求、复位请求、完成状态、故障状态。主循环里只是调用这三个功能块,并根据它们的完成和故障状态做整体的流程衔接。

这样一来,任何人拿到程序,先看主循环就知道整个系统的骨架,然后进入每个功能块去看细节。而且三个工位之间天然隔离,一个工位的程序内部改坏了,不至于把其他工位的逻辑也带崩。这种结构虽然前期规划要多花一点时间,但后期省下的时间一定远超前期投入。

还有一个被很多人忽略的点:程序版本管理。尤其是在厂内做了三四轮改造之后,如果没有版本记录,你根本不知道当前跑在设备上的程序是哪个版本,出了力也改错了地方。我的习惯是在程序信息里写清版本号、修改日期、修改内容摘要,同时在数据块里存一个版本字符串,配合上位机显示,方便现场人员随时确认。

4.3 注释:写出"为什么"而不是"是什么"

很多工程师写注释喜欢写废话,比如"启动电机"、"气缸伸出"。这种注释对读者毫无帮助,因为程序本身已经表达了这个意图。

真正有价值的注释应该回答"为什么"和"要注意什么"。例如:

  • 为什么这里要延时3秒?因为要等润滑泵压力建立,直接启动会磨损导轨。
  • 为什么用下降沿触发复位?因为操作工按住复位不放的时候,优先级不能覆盖下一个启动请求。
  • 为什么这两个信号要取反?因为传感器用的是常闭触点,断开才表示正常。

这种带着因果链的注释,才是后期维护的真正救星。很多时候你翻翻注释,就能理解当初设计的来龙去脉,而不必靠猜。

4.4 故障诊断设计:让程序自己"说话"

一个写得好程序,应该像一个好的设备操作说明书,甚至比说明书更有用。设备出了问题,程序应该能告诉你问题是什么、在哪、大概什么原因。

我强烈建议在每个设备动作上加上"执行超时检测":发出动作指令后,如果在设定时间内没有收到动作完成信号,立即停止后续动作,同时置位对应的报警位,并把报警文本传到人机界面。操作工不用猜,看一眼界面就知道"二号夹爪伸出超时",然后去查那个气缸的电磁阀和到位开关。

故障复位也要设计好。原则是:只有在所有导致故障的条件都消失之后,复位按钮才有效;复位之后设备必须自动回到安全的初始状态,而不是停留在故障那一刻的输出状态上。这个细节不处理好,操作工按完复位之后设备突然动起来,是会出安全事故的。

还有一类诊断很容易被忽略:输入信号的合理性校验。比如模拟量液位计的量程是4到20毫安对应0到100度,但如果线断了,信号会掉到0毫安以下,程序如果不去做超量程判断,就会把"断线"当成"0度"去参与控制,带来灾难性的后果。正确做法是对每个模拟量输入做范围检查,信号超限必须报故障并进入安全状态。

5. 常见问题与实战排查经验实录

5.1 那些"能运行"但藏着隐患的程序特征

我在帮别人做技术支持和项目改造时,总结过一份"故障高发人群"清单。程序有以下特征的,基本就是定时炸弹:

第一类是用了大量M中间变量沟通逻辑的。M变量不分彼此,谁都能读能写,一旦网络逻辑多了,很容易出现两个地方同时写同一个位,输出状态乱跳。对这种现象,排查手段往往是"注释掉一段试试",效率极低。

第二类是梯形图里大量使用CJ和JMP跳转的。PLC里的跳转可以改变扫描顺序,但也让程序执行路径变得不可预测。我从没见过哪份跳转一大堆的程序是可维护的,调试时还好,一到改造就抓瞎。

第三类是模拟量没有滤波、没有量程保护、没有断线检测的。信号一抖动,设备就开始神经质,产量上不去还找不到原因,最后往往是花了好几天才发现是一个变送器接地不良,而程序本身根本没有任何提示。

第四类是程序块和HMI画面里的故障文案各写各的,报警文本跟实际变量对不上号。维修工明明是报警"气缸伸出超时",赶到现场一查是另外一个气缸在报故障,纯粹被文本耽误了时间。

5.2 我踩过的坑和教训

我自己也吃过不少亏。最早写程序的时候,我也特别自信,能把设备"带正常"就觉得完工了。结果有一次改造工位,需要修改一个公共气缸的延时参数,我愣是搜出二十几处硬编码的延时定时器,改了上半夜才改完,第二天上线又发现有一处漏改,设备直接撞机。从那之后,我再也不写硬编码的延时参数了,全部抽到配方数据块或者可调参数里,界面能改、程序能读,一个参数只维护一处。

还有一次,遇到过气缸到位信号没接到,程序一直在启动和等待之间反复试探。当时梯形图里没有超时检测,也没有故障锁定,气缸三个小时之内来回动作了上百次,最后机械结构都松了。这个案例给我留下极深的印象,从那以后,"任何动作都要有超时保护"就成了我写程序的铁律,没有例外。

所以我现在的习惯是,写完程序之后,先自己扮演"维修工"角色,把容易藏故障的地方全部审视一遍。模拟一下:通迅断了会怎样?气缸卡了会怎样?传感器坏了会怎样?操作工误触了会怎样?把这些"异常剧本"全部在逻辑上过一遍,确认每个异常都有明确的报警、动作都被锁定、状态可恢复,我才敢把程序交付到现场调试。

6. 结尾:一点个人体会

回到标题那句话,"PLC程序能运行,就算写得好吗?"——我现在可以很确定地说:能运行只是及格线。程序写得好不好,要看它在故障面前稳不稳、在维护方面便不便、在改造之时活不活。真正的成就感,不在于调试那天设备多么顺畅地跑起来,而在于几年之后,新来的工程师拿着手册能快速看懂你的逻辑,维修部门不再半夜打电话找出处,老板再也不骂"这破程序到底是谁写的"。

最后再分享一个小技巧:每次写完一段逻辑,试着把它讲给旁边不懂这套程序的人听。如果对方在你不动手指的情况下,只靠听和看就能理解程序干了什么、为什么这么干、卡住了怎么查,那这段程序基本就是"写得好"的。写程序这件事,发展到最后拼的其实不是指令熟不熟,而是你能不能把复杂藏在简单里,把安全融在结构里。共勉。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询