前两天帮人看一台老设备改PLC控制的图纸,我盯着梯形图看了半天,发现一个特别典型的错误:急停按钮在程序里接成了常闭触点。结果现场一按急停,电机反而启动,把人吓出一身冷汗。这个错误说到底,不是指令记不住,而是没真正理解PLC最基础的指令到底是怎么工作的。
今天这篇东西,我就把PLC基本指令按实战顺序完整讲一遍。不光是列出LD、OUT、SET、RST这些助记符,更要讲清楚每个指令背后的PLC工作机制,以及真正调程序时那些容易踩的坑。内容适合两类人看:一是刚接触PLC、被指令表搞得晕头转向的新手;二是会接线、会看图纸,但刚转做编程的电工师傅。看完你就会明白,基本指令不难,难的是理解PLC这台“机器”的思考节奏,和硬接线完全不一样。
1. 扫描周期是所有PLC指令的“总开关”——先别急着记指令
1.1 PLC的“读、算、写”三步曲
很多人第一次接触PLC时,会把梯形图想象成一张继电器电路图,觉得电流从左母线流到右母线,触点一碰就通。这个方向性的理解没有错,但漏掉了最核心的东西:PLC不是一根根导线直接连着的,它是靠扫描周期一次次刷出来的。
所谓扫描周期,就是PLC在极端时间里不断循环执行三个动作:读输入、算程序、写输出。CPU先读取所有输入端子上的电平状态,存到内存里的输入映像区;然后从程序的第一条指令开始逐条执行,直到END结束;最后把计算得到的输出结果写到输出映像区,传送到端子。
我习惯把它类比成一个保安:每隔几毫秒就拿着登记表看一遍门口进来的人,把状态记下来,然后按规则把指令发给各个岗位,再继续下一轮。你给它的信号,要等下一轮“点名”时才会被它看到。这也是为什么有些很短的脉冲信号,PLC偶尔“没反应”——不是坏了,是它在两次扫描之间错过了。
1.2 硬接线是并联思维,梯形图是串行思维
传统继电器电路里,一个启动按钮可以同时带好几个接触器线圈,物理线路上是并联的。只要按钮按下去,所有回路同时得电。但PLC里完全不同:一段梯形图是从上到下、从左到右逐条扫描的。你写的每条指令都有先后顺序,前面的运算结果会直接影响后面的指令状态。
举个例子,程序第一段里你用X0驱动Y0,第二段里又用Y0的常开触点去驱动Y1。那么Y0这段必须在Y1这段之前执行,Y1才能在下一次扫描里被正确驱动。如果程序顺序写反了,或者搞了跳转,结果就会变得莫名其妙。
再比如说,同一个X0在程序前段被用做输出条件,在后段被用做计数条件。按硬接线的思路,X0就是一个常开触点,按多久就接通多久。可在PLC里,X0状态一旦为ON,程序每一轮扫描都会在后段看到它为ON,计数指令就会每个周期都触发一次,而不是“按一下计一次”。这种差异,是新手最容易理解不了的地方。
1.3 响应时间怎么算,调试时怎么查
既然PLC是周期性刷新的,那从按钮按下到执行器动作,中间必然有延迟。大致公式:输入滤波时间 + 程序扫描时间 + 输出刷新延迟。
输入滤波时间一般是几毫秒到十几毫秒,取决于PLC硬件和你在参数里设置的滤波值;程序扫描时间则由程序步数和指令类型决定,通常几毫秒到几十毫秒;输出延迟主要是输出端子的继电器或晶体管动作时间。所以一个普通按钮从按下到指示灯亮,几十毫秒是正常的。
我调试时经常被问到“为什么我按下按钮,输出好像顿了一下才动?”——如果不是延迟时间异常地长,比如几秒钟,那多半是程序里逻辑条件的问题,而不是响应速度的问题。这时候我会先做两件事:第一,看输入指示灯有没有亮,确认信号是不是进了PLC;第二,在监控软件里看这个输入点位、输出点位的实时状态,看问题是出在“没读到”还是“程序没算出来”。如果没有输入指示,我还会用强制功能把某个输入点位暂时变成ON,验证程序后面的逻辑是否正确。但这里要强调一句:强制功能一定要谨慎,试完立刻取消,否则检修期间可能出安全事故。
2. 位逻辑三件套:常开、常闭和线圈,藏着不少反直觉的坑
2.1 LD、LDI、OUT,梯形图的地基
位逻辑是PLC程序的基石,所有逻辑控制都建立在这几个指令上。LD表示“一个常开触点开始”,LDI表示“一个常闭触点开始”,OUT是“线圈输出”。
比如最经典的启保停电路,用指令表写出来是:
LD X0 // 启动按钮 OR Y0 // 自锁触点 ANI X1 // 停止按钮常闭 OUT Y0 // 输出线圈意思是:X0按下,或者Y0已经导通,同时X1没有按下,就把Y0置为ON。这种写法和梯形图画出来是一一对应的:左边母线出发,X0和Y0的常开触点并联,然后串X1的常闭触点,最后接Y0线圈。理解触点指令的关键是:常开触点在位为ON时导通,常闭触点在位为OFF时导通。这句话看着简单,实际编程时80%的初学者都会在这个上面栽跟头。
2.2 急停按钮:外部常闭,程序里却要用常开
回到文章开头的例子。急停按钮在电气硬接线里,按惯例一定是串常闭触点,急停按下时回路断开,设备断电。可是同样的硬件接到PLC输入端子后,情况就反过来了。
外部急停接常闭触点,意味着正常情况下,这个输入点一直是接通的,输入位X0始终等于ON。按下急停,输入位X0变成OFF。程序里要表达“急停没按下时允许运行”,就应该用X0的常开触点:X0为ON时条件通过,X0为OFF时条件断开。反过来,如果照抄硬接线的习惯,程序里用X0的常闭触点,那正常时X0为ON,常闭触点反而是断开的;急停按下后X0变成OFF,常闭触点反而导通——设备当然会在急停时启动了。
这个错踩的人太多了。包括安全门开关、行程开关、磁簧开关,只要外部用的是常闭触点,程序里通常都要转成常开触点来理解。另外,外部常闭接法还有一个好处:一旦输入线路断线,输入位会变OFF,设备也能安全停下,这是fail-safe的思想。条件允许的话,输入断线报警也建议加上,否则分不清是“急停被按下”还是“线断了”。
2.3 双线圈问题:同一个Y0别写两次
双线圈是新手程序里最常见但又最隐蔽的问题。简单说就是同一个输出点Y0,在不同程序段里被写了好几次OUT Y0。CPU执行程序时,后面的OUT会把Y0重新赋值,覆盖前面所有计算结果。
举个例子:第一段X0为ON时OUT Y0;第二段X1为ON时又OUT Y0。如果X0和X1都ON,Y0到底通不通,取决于最后执行的那段,也就是第二段。如果第二段条件不满足,即使第一段满足,Y0也还是OFF。很多人监控时看到Y0状态和想象中不一样,找半天原因,最后发现就是双线圈覆盖。
解决办法有三种:
- 合并逻辑:把两个条件用AND、OR汇总到一个OUT,适合逻辑简单的情况;
- 用中间继电器:M点做中间变量,最后统一用一个OUT Y0;
- 用SET/RST:适合状态锁存场景,比如启停控制。
排查技巧很简单:在编程软件里搜索Y0的“OUT”出现几次。一旦出现两次以上,就基本可以断定这里有双线圈隐患。
3. 自锁、互锁和SET/RST:教科书没写的使用边界
3.1 起保停电路的“保”是怎么来的
说完了双线圈,自然要讲自锁。自锁电路是PLC控制里最基础也最重要的结构。上面的启保停程序里,Y0导通后,它会通过自己的常开触点维持回路,即使X0已经松开,Y0也依然保持为ON。直到X1常闭触点被断开,回路才会被切断。
这里有个容易忽略的细节:启动按钮应该用常开按钮,不能自己带自锁。如果用了带机械自锁的按钮,X0按下一次后一直保持ON,程序里自锁反而变得多余,停止逻辑也会变得奇怪。还有,启动条件X0不要加边沿指令,否则按下瞬间只导通一个扫描周期,自锁还没来得及形成,输出就可能直接停了。你可能会问,为什么差不多的结构,用SET/RST也能实现启停。这就引出了下一小节。
3.2 SET/RST和OUT的本质区别
OUT指令是“每次扫描都根据条件刷新”,条件一消失输出就断。而SET/RST是“锁存型”的:SET M0之后,M0会一直保持ON,哪怕触发条件已经消失,直到你执行RST M0才变OFF。
这两种指令该怎么选,我的经验是:普通启停用OUT+自锁,状态锁存用SET/RST。比如故障报警,故障条件出现时SET M100,M100一直保持ON,即便故障信号消失了,报警灯也还亮着,必须按复位按钮执行RST M100才熄灭。这个场景用OUT+自锁也能实现,但代码会绕,而且很容易在复位逻辑里出岔子。SET/RST程序结构一目了然:什么条件置位,什么条件复位,清清楚楚。
但是反过来,电机启停我一般不推荐用SET/RST。尤其是不要用“启动按钮SET输出、停止按钮RST输出”这种写法。因为一旦程序逻辑里某个分支出了错,或者复位条件没触发,输出就会一直保持,不能像OUT那样每周期自动刷新。真正的安全联锁还是要靠外部硬件回路加程序逻辑。
有个小技巧:如果同一个周期里既满足置位条件又满足复位条件,程序执行到后面的语句时,后写的那条指令会覆盖前一条。所以复位指令建议写在置位指令后面,或者明确复位优先,避免状态不确定。
3.3 正反转互锁:程序互锁之外,硬件互锁不能省
互锁电路在电机正反转控制里是必修课。程序里的做法很简单:正转输出Y1的回路里串反转输出Y2的常闭触点,反转回路里也串Y1的常闭触点。这样Y1导通时,Y2就不可能导通,反之亦然。
但只做程序互锁并不保险。交流接触器动作是毫秒级的,从线圈得电到主触点闭合,以及从线圈失电到触点完全断开,都有延迟。如果正转接触器和反转接触器动作时间不一致,完全可能在程序互锁生效之前,出现一瞬间两个接触器都吸合,造成相间短路。所以,接触器本身必须加机械/电气硬件互锁,程序里也要写软件互锁,两边都不能少。
另一个经验是:很多设备并不需要在正反转之间瞬间切换,建议先停后启,或者加延时。即使程序允许直接反向,机械冲击、电流冲击都很大,时间久了传动机构容易坏。我在调这类设备时,通常会在正转运行状态下,让反转启动指令先断开正转输出,延时几百毫秒后再启动反转。
4. 定时器与计数器:参数表背下来,不如踩几个坑记得牢
4.1 三种定时器的应用选择
定时器是PLC里最常用的指令,没有之一。基本的三类得搞清楚:
| 指令类型 | 行为描述 | 典型应用 |
|---|---|---|
| TON | 条件ON后开始计时,时间到输出ON;条件OFF,当前值清零,输出OFF | 电机启动后延时开冷却阀 |
| TOF | 条件ON时输出立即ON;条件变OFF后开始计时,计时期间输出保持ON,时间到输出OFF | 输送带停机后延时断除尘风机 |
| TONR | 条件ON计时,条件OFF时保持当前值,再次ON继续计时,累计到设定值后输出ON | 电机累计运行时间统计 |
TONR一定要有复位指令,比如RST T0,否则计时值一直保存,不会自己清零。这一点在实际维护时经常被忽视:设备明明没有运行,可某个“累计运行”状态始终是ON,就是因为没人触发复位。
4.2 定时器最坑的三个细节
第一个坑是时基和编号范围。不同品牌、甚至同一品牌不同系列,定时器的编号范围、时基都不一样。比如某款日系PLC,T0到T199是100ms时基,T200到T245是10ms时基;另一款德系PLC的定时器编号又是另一套规则。设定值K50配100ms时基,定时时间就是5秒;配10ms时基就变成0.5秒。写程序前先查手册,别看别人程序里写K50自己也照抄,结果动作时间完全对不上。
第二个坑是同一个定时器编号在多处使用。有的编程软件会报重复定义,有的不报错但悄无声息地让后一段覆盖前一段。哪怕两段程序互斥、理论上不会同时执行,我也不建议复用同一个编号——程序可读性会变得极差,后来维护的人根本不敢改。
第三个坑是定时器精度与扫描周期的关系。普通定时器是在扫描周期内检查时间基准的,所以定时误差大约是一个扫描周期。如果扫描周期20ms,那一个100ms的定时器实际动作时间可能在100到120ms之间波动。常规设备无所谓,但讲究时序配合、或者几个定时器联动的场合,误差就可能累积成故障。
另外补充一句:高速信号计数、高频脉宽测量,就不要指望普通定时器了,那属于高速计数、硬件中断或专用高速定时指令的范畴。这也是为什么有人发现接近开关输出频率很高时,计数器会丢脉冲——普通计数器跟不上。
4.3 计数器:不只是数个数
计数器指令CTU是上升沿计数:输入从OFF变ON一次,当前值加1,达到设定值后输出ON。CTD是减计数,从设定值往下数到0。复位一般用RST指令。
计数器的输入必须是“边沿”,不是电平。所以前面那段说X0持续为ON时,普通计数器的当前值不会一直增加,只有从OFF变ON那次才加一。理解这一点,才能明白为什么计数器经常要和边沿指令、或脉冲信号配合用。
典型应用是接近开关计产品数量、编码器脉冲计长度。这里提醒一下:普通计数器输入有滤波延迟,信号频率太高会漏计,高速场合必须用高速计数器,并配合高速输入端子。我见过有人用一个普通计数器接编码器A相脉冲,速度一上来数字直接乱飞,查了半天以为是接线干扰,其实是用错了计数器类型。
4.4 串起来的小例子:混料罐搅拌、延时、排料和批次计数
用刚才讲的指令,串一个小项目感受一下完整逻辑。假设一个混料罐:按下启动按钮X0,搅拌电机Y0开始运行;10秒后打开排料阀Y1;排料5秒后关闭阀门,并记录一批完成;累计完成10批后报警灯Y2亮。
LD X0 OR M0 ANI X1 // 停止按钮 OUT M0 // 运行状态 LD M0 OUT Y0 // 搅拌电机运行 OUT T0 K100 // T0延时10秒(以100ms时基为例) LD T0 OUT Y1 // 打开排料阀 OUT T1 K50 // T1延时5秒 LD T1 OUT Y1 // 关闭排料阀 LD T1 DF M1 // T1上升沿脉冲 LD M1 OUT C0 K10 // 批次计数 LD C0 OUT Y2 // 累计10批报警这个例子看起来简单,但已经把位逻辑、定时器、计数器、边沿指令全部串起来了。C0达到设定值后Y2亮,再往后如果要自动清零继续下一轮,就需要RST C0等逻辑。真实工程里还会加上手动/自动切换、阀门反馈检测、急停联锁,但基本骨架就是这套。
5. 边沿、比较与运算指令:当程序不再只是“通和断”
5.1 边沿指令:让按钮“按一次只算一次”
前面讲过,PLC扫描周期快,按钮按一次的物理时间往往能持续好几个扫描周期。如果直接用X0驱动计数器,一次手按就可能让计数器加好几次。所以要靠边沿指令把“按下”变成“一个扫描周期的脉冲”。
上升沿指令(有的PLC写作PLS、DF、EU,叫法不同)在输入从OFF变ON的那一个扫描周期里,输出一个扫描周期长的脉冲;下降沿指令(PLF、DFI、ED)则在ON变OFF时产生脉冲。典型用法是加计数、减计数、状态切换、顺序步进。
例如:
LD X0 DF M0 // X0上升沿,M0通一个扫描周期 LD M0 OUT C0 K10 // 每按一次X0,C0加1注意,边沿产生的脉冲非常短,只有几个毫秒甚至更短,如果它驱动的不是SET/RST或计数器这类有记忆功能的指令,而是OUT线圈,那线圈几乎不会稳定导通,看起来就像完全没反应。这也是很多人误以为边沿指令“不好用”的根本原因。
5.2 比较指令:从逻辑判断到数值判断
位逻辑只能判断“通/断”,但工业现场大量需求是“温度太高就报警”“液位太低就开阀”“速度到多少就换挡”。这时候就要用比较指令。
比较指令有两种常见写法:一种是触点型,比如LD>=、AND<,直接像触点一样串在线路里;另一种是CMP指令,一次比较后会产生“大于、等于、小于”三个标志位。不同PLC格式不同,但用法都是先比较两个数值,再根据结果决定后面的运算块是否执行。
举例:温度D100大于等于60度时报警M20,小于50度时复位。配合滞回区间:
LD>= D100 K60 OUT M20 LD< D100 K50 RST M20为什么中间留出50到60这段滞回?如果没有滞回,只在60度时亮、低于60度灭,温度在60度附近波动时,报警会反复通断,压缩机或阀门会频繁启停,很快损坏。有了滞回区间,就稳定得多。这个思路在实际工程里非常常用。
5.3 加减乘除:基本指令里的“计算器”
运算指令ADD、SUB、MUL、DIV在基本指令里也有一席之地。比如把两个计数器数值做差,得到实际产量;把批次号加一;把模拟量转换后的数值乘个系数再传到上位机。
用运算指令要注意数据类型:整数除法会截断余数,需要小数的场合要用浮点数指令,或者先把数值放大再除,最后再缩回去。比较指令也要注意有符号数和无符号数的区别,别把一个很大的无符号数值当成负数来比较,那结果会完全反掉。
我的建议是,控制逻辑里的复杂运算不要全堆在梯形图里,能用功能块、结构化文本解决的,尽量拆出去。基本指令适合处理整齐、直观的运算,硬要用几十行梯形图去算一个配方公式,维护的人会想打人。
最后分享一点个人体会
我最早也是从看继电器图纸转做PLC编程的,最大的坎不是指令记不住,而是脑子里总在画“线”,画不出来“扫描”的感觉。后来养成了几个习惯:拿到一台没接触过的PLC,先翻编程手册里的指令一览表和时间基准表;写完程序把所有输入、输出、中间继电器全部写注释;调试前先在脑子里把每个扫描周期过一遍,看看有没有哪个输出被多次赋值、哪个定时器编号被重复使用。
基本指令的组合千变万化,但说到底就三句话:什么时候导通,什么时候保持,什么时候复位。把这种节奏感建立起来,你再看任何品牌的梯形图,都会觉得它们其实是同一套逻辑换了件马甲。希望这番讲解能帮你少走点弯路。