
1. 从一次“不算故障”的故障说起为什么要碰中断做PLC编程这些年我最怕听到的一句话是“设备偶尔出问题还没规律”。前阵子处理的一台包装机就是典型计数偶尔多几个断料检测总是慢半拍伺服到位信号明明亮了程序却像没看见。查来查去IO信号正常、程序逻辑正常、通讯正常最后才发现问题出在扫描周期上——不是坏的是根本来不及。那台设备扫描周期不算慢但也在8毫秒左右飘。计数脉冲来了两三个程序才扫描一次丢脉冲是必然的。你让PLC用“轮询”的方式去抓“偶然发生”的信号本质上就是一个保安在操场上一圈一圈巡逻小偷非要从他背后溜过去他也没办法。PLC的循环扫描机制和中断机制就是这个区别。中断在PLC里不是什么神秘功能它就是一个软硬件协同的“插队机制”。外部信号来了CPU把手头的事停一下先把中断程序按优先级跑完再回来接着干原来的活。核心价值就一句话对特定事件的响应延迟不再取决于扫描周期而是取决于硬件响应速度和中断程序的执行时间。这篇文章我想系统讲一遍PLC中断功能的使用从硬件配置、触发方式、程序编写到调试避坑都用实际项目的经验来讲。适合谁看刚接触中断、不知道怎么下手的初学者以及写过中断但遇到过触发不稳定、程序偶发异常、响应延迟超预期的老手都能从里面找到点东西。中断不是万能的但很多“扫描周期解决不了”的问题它确实是正解。2. 中断的本质理解CPU的“插队机制”2.1 循环扫描与中断响应的区别先用一个生活类比说透PLC正常运行时的逻辑是一个永不停歇的循环读取输入、执行程序、刷新输出然后从头再来。这个循环的周期就是扫描周期。扫描周期是PLC工作的基础但也是很多实时性问题的来源——程序越长、IO越多、通讯任务越重扫描周期就越长对外部事件的响应就越迟钝。把PLC比作一个服务员循环扫描就是按顺序给每桌客人上菜。你程序里的每一行指令都是一个客人每个人都要等到轮到自己才会被处理。而中断相当于一个VIP客人按了服务铃——服务员会放下手里的菜先去处理VIP的需求处理完再回来接着上菜。在PLC的世界里这个“服务铃”就是外部信号这个“VIP处理流程”就是中断程序中断服务子程序。这里要强调的是中断程序不是被“调用”的而是被“触发”的。普通子程序需要你在主程序里写CALL指令走到那一行才执行中断程序不需要主程序里去写调用只要中断条件满足CPU会自动跳过去执行。这个“自动跳转”的过程硬件上是有固定开销的——一般PLC在几微秒到几十微秒之间远小于扫描周期。正因为有这个硬件级的跳转机制中断才能做到“和扫描周期无关”的快速响应。2.2 中断不是“越快越好”扫描周期、响应时间、抖动时间三个参数要分清很多工程师一碰中断就犯一个误解觉得用了中断响应时间就是0。实际不是。中断响应由三个时间叠加组成硬件滤波时间信号从输入端进入PLC首先要过输入滤波电路。滤波是抗干扰的必要手段但也带来了延时。这个时间可以从参数里调下面章节我会专门讲怎么选。中断响应时间中断延迟从信号到达CPU、到CPU开始执行中断程序第一行指令的时间。这个时间主要由CPU内部机制决定不同品牌型号差异很大一般在几十微秒到几百微秒。中断程序执行时间你的中断程序本身跑完需要多久。这部分是你可以控制的但也是很多人忽略的——中断程序里写大量复杂运算响应速度照样起不来。综合考虑这三个时间中断对事件的响应总延迟往往是几十微秒到一两毫秒级别而不是扫描周期的几十毫秒级别。关键不在于追求绝对快而在于把响应时间从“扫描周期的量级”降到“硬件响应的量级”。还有一个概念叫“抖动时间Jitter”——同样是触发一次中断每一次响应时间并不是完全一致的。对于精密的运动控制、测量同步这类场景抖动比平均响应时间更值得关注。如果要做微秒级同步光靠PLC内置中断可能不够得考虑支持硬件同步的专门方案。PLC中断适合的是“毫秒级甚至亚毫秒级的确定性响应”这个定位要清楚。3. 动手前必须搞懂的事硬件配置与中断源规划3.1 先搞清楚你的PLC支持哪些中断源不同品牌的PLC中断源的种类差异很大。但归纳起来绝大部分PLC的中断源逃不出这几类外部输入中断也叫外中断由输入端子上的信号边沿触发。比如某个输入端从OFF变ON、或者从ON变OFF都可以触发一次中断。这是使用最频繁的中断类型。高速计数器中断当高速计数器达到设定值、或者发生计数方向变化时触发。这类中断常用于编码器计数、脉冲定位和测速。需要说明的是很多PLC的高速计数器是和特定输入端子绑定的不是所有输入端都能接高速计数。定时中断每间隔固定时间自动触发。比如每10毫秒执行一次中断程序常用来做周期性的数据采集、通讯报文发送、PID运算等。通讯中断比如收到指定长度的数据、通讯出错时触发。这个在MODBUS、自由口通讯里用得比较多。定位模块相关中断某些运动控制型PLC支持原点回归完成、定位完成等中断。规划中断源时第一件事不是写程序而是翻手册。你需要确认三件事哪些输入端子支持中断、这些端子是否和高速计数器/普通IO复用、中断号是如何分配的。以我常用的某主流品牌为例它的中断输入是绑定在特定的几个输入端上的同一个物理端子既可以配置成普通输入、也可以配置成高速计数器、也可以配置成中断输入三者只能取其一。3.2 中断输入端的特殊性接线方式和平常不一样普通输入端子接法就是把传感器信号接进去PLC内部有光电隔离、有RC滤波处理完再送给CPU。但中断输入端在硬件上有一条独立的快速通路到CPU中断控制器这也就意味着它对信号的电气要求和普通输入不完全一样。几个容易踩的坑先说一下第一输入电压范围要符合高速输入的要求。很多PLC的普通输入端支持PNP/NPN切换、支持12-24V宽范围但高速中断输入通常要更规范的电平最稳妥的是用传感器供电一致的24V不要试图用5V信号直接接除非你确定该PLC的高速输入支持5V差分信号。第二中断输入端千万不要和感性负载并联。中断输入的抗干扰设计虽然比普通输入好但本质还是对边沿敏感如果一条线上既有传感器信号、又有继电器线圈或接触器线圈断电瞬间的反向电动势很容易造成误触发中断。我的做法是所有中断输入的传感器电缆单独走线远离动力线屏蔽层单端接地接地端就在PLC侧。第三注意输入极性选择。有些PLC高速输入端子支持“源型输入”和“漏型输入”配置接线前要看清楚用的是哪个类型的传感器。NPN传感器接漏型、PNP传感器接源型这是基础但高速输入端如果配错了极性通常不是完全没信号而是信号飘忽、偶发触发——这种问题排查起来比完全没信号更费时间。3.3 中断类型怎么选沿触发、状态触发还是定时触发把中断源弄清楚后下一步就是选择触发方式。多数PLC支持上升沿触发、下降沿触发、以及状态电平触发中的一种或多种。这里说个很多初学者不太注意的点上升沿和下降沿对应的传感器类型是不同的。光电传感器大多数是PNP输出信号平时是0V检测到目标时输出24V这叫上升沿触发如果是NPN传感器平时输出24V检测到目标时拉低为0V那就是下降沿触发。你在配置中断触发方式之前先确认一遍传感器的输出逻辑而不是到了现场才发现反了。状态触发和沿触发最大的区别在于状态触发要求信号保持一定时间而沿触发只要检测到一个“跳变”就响应。因此对有保持时间的信号比如接近开关检测到位用状态触发可以避免信号抖动引起的多次触发而对快脉冲信号比如编码器输出、流量计脉冲只能用沿触发因为信号保持时间太短状态触发根本来不及。定时中断的概念也值得强调它不依赖于外部信号而是CPU内部定时器精确触发。如果你需要“每5毫秒采样一次模拟量并存储”“每50毫秒发送一次通讯报文”这种周期性任务定时中断是最干净的方案——不需要自己在主程序里做时间片轮询也避免了扫描周期不稳定带来的周期抖动。4. 被很多人忽略的两个“隐形配置”分频器和滤波器4.1 输入滤波器你调得越激进中断越容易被干扰我在现场处理过很多“中断动不动就误触发”的问题最后排查下来相当一大部分不是硬件坏了、也不是程序错而是滤波参数没配对。输入滤波器的本质是一个RC低通电路加数字去抖逻辑用来过滤信号中的毛刺和噪声。但这个滤波器是“一视同仁”的——它不仅滤掉了噪声也会滤掉你真正想要的短脉冲信号。如果滤波时间设得过大比如默认的10毫秒而你的编码器输出脉冲宽度只有1毫秒那这个脉冲在进入CPU之前就已经被“滤没”了中断当然不触发。反过来如果你的应用是普通开关信号信号本身倒是有几十个毫秒的稳定电平但你为了“反应快”把滤波时间设到了0.01毫秒那现场电机的每一次启停、每一个接触器的吸合都可能通过电磁耦合产生干扰脉冲然后被这个极度灵敏的输入通道当成“有效边沿”捕捉到导致中断乱触发。滤波时间不是一个“越小越好”的参数它本质上是一个跟信号质量和最小有效脉宽相关的权衡参数。我的建议是先测出信号的最窄有效脉宽用示波器量得最准然后把滤波时间设置成该脉宽的1/5到1/3。比如编码器输出最小脉宽约0.5毫秒滤波设为0.1毫秒左右就比较稳妥。既有足够的抗干扰余量又不至于把有效信号滤掉。4.2 分频器编码器信号进中断前可能要“降频”编码器与PLC高速计数/中断配合时还有一个参数容易被忽略——分频系数。编码器分辨率动辄每转几百几千个脉冲如果你把编码器的每个脉冲都送进中断CPU会大量时间花在中断处理上主程序反而被拖慢。分频器的意义就是让编码器每产生N个脉冲才往中断控制器送1个脉冲。对于线数很高的编码器配合分频器使用是让CPU“喘口气”的关键手段。但这带来一个新问题分频之后中断程序里的计数和实际物理位移之间的对应关系变了。原来每转3600个脉冲对应一圈360度分频4倍后变成每转900个脉冲才触发一次中断那么中断程序里计算角度、位置时要乘以分频系数否则位置换算就错了。很多人在这上面出过精度偏差问题调试时务必把分频系数纳入计算。这里还要特别提醒一个容易踩的坑分频器并不是PLC中断功能的标准配置它一般集成在高速计数器功能里。如果你使用的中断恰好需要“每累计N个脉冲触发一次”很多PLC的高速计数器本身就支持“设定值匹配中断”或者“计数达到预设值触发中断”这正是分频功能的替代方案——不要硬在外部电路加一个CD4017分频芯片除非你确实需要的是硬件分频用PLC的计数器匹配中断更灵活、更容易修改参数。5. 实战配置一台“计数断料检测”设备的中断完整方案5.1 设备背景和需求分析为什么要用中断而不是改扫描周期为了把上面这些概念串起来我用一个实际项目来做完整演示。设备是一台包装机上的送料检测单元核心需求有两个一是计数需求送料辊上装有编码器每送过一个产品编码器输出若干脉冲。要求准确统计产品数量误差必须为0。现场测试表明PLC扫描周期约7毫秒而编码器脉冲间隔最快可到0.5毫秒一个扫描周期内可能丢失多个脉冲。二是断料检测需求薄膜卷料断裂时会有一个机械式断料检测杆动作输出一个开关信号要求控制系统在1毫秒内完成报警并停止伺服否则会浪费一大段薄膜。面对这两个需求第一反应当然是“尽量缩小扫描周期”。但那台设备的程序和通讯任务已经是这个规模了强行优化到0.5毫秒级根本不现实。再退一步即使扫描周期可以缩短扫描机制下CPU“看到”外部信号的更新时刻仍然受限于扫描周期的边界不可能做到“信号一到达就马上处理”。所以这里只能上中断。5.2 硬件接线的完整规划三个关键通道基于上面的需求我做了如下规划编码器A相接到支持高速计数器/中断的输入端子X0用于计数断料检测杆的信号接到中断输入端子X1用于断料报警伺服V-REF信号接到X2暂不使用中断功能只是备用其余设备IO继续使用普通输入端子。这里要强调的是接到X1的断料信号不能用普通输入端子的通道传递。原因我在上文说过普通输入要过滤波、过输入映像刷新、等扫描周期这几层下来可能多出好几毫秒的延迟。而X1作为中断输入从信号电平跳变到中断程序执行硬件路径是独立的快速通道。接线时的几个细节编码器使用双绞屏蔽线屏蔽层在PLC侧接了PE传感器侧悬空断料检测杆的开关是机械触点我额外并联了一个RC灭弧电路电阻约100欧姆串联电容约0.1微法防止触点抖动和电弧产生连续误触发两根中断信号线都和动力线分开走间距至少20厘米实在避免不了交叉时垂直相交。5.3 中断参数配置与初始化程序一步一步对着做以该品牌PLC为例参数配置大致分下面几步具体菜单名称不同品牌略有差异思路通用第一步分配中断输入端子。在系统参数里把X0配置为高速计数器模式、X1配置为中断输入模式。注意这一步必须在程序下载前完成因为PLC大部分IO配置在运行期间不能修改。第二步初始化高速计数器。在第一次扫描时执行初始化程序设定计数模式、分频比、计数方向等。我的参数是A/B正交模式4倍频计数范围是32位有符号数。第三步注册中断程序。将X1的上升沿与中断程序关联。这一步通常使用专门的指令常见的是ATI或类似指令把“第几号中断”和“哪个中断程序”绑定起来。代码大概是这样// 第一次扫描初始化 IF FirstScan THEN // 设定高速计数器的计数模式 SetHSCMode(HSC0, HSC_MODE_AB_4X); // 清零计数器 HSC0 : 0; // 将X1的上升沿触发的中断关联到中断程序INT_BREAK_DETECT ATI(INT_X1_RISE, INT_BREAK_DETECT); END_IF;第四步编写中断服务程序。中断程序的内容要尽量精简原则是“快进快出”。以断料检测为例中断程序里要做的事就三件置一个断料标志位、记录当前计数器的值作为停机位置参考、触发伺服急停。把那些繁琐的报警文本、触摸屏数据更新全部放到主程序里去做。// 中断服务子程序断料检测响应 PROGRAM INT_BREAK_DETECT; BEGIN // 记录当前计数位置 g_break_pos : HSC0; // 置断料标志主程序看到标志后执行屏显/报警等慢速动作 g_break_flag : TRUE; // 直接关闭伺服使能最快停止安全第一 Servo_Enable : FALSE; END_PROGRAM;5.4 调试过程中的实测记录响应时间到底提升了多少程序写好、硬件接好之后进入调试阶段。我用存储示波器同时测量了断料检测杆信号和伺服使能输出的波形实际测试结果如下表项目改造前普通扫描改造后中断方式信号到伺服停止的响应时间7~15毫秒随扫描周期波动0.8~1.2毫秒计数误差每1000个丢2~3个0连续测试5万次无丢失CPU占用增加—约3%程序复杂度增加—低中断程序共6行数据说明这个方案是成立的。响应时间从“十几毫秒”降到了“亚毫秒级”而且这个时间不再飘忽不定而是变得稳定——这是中断相比扫描机制的一个隐形优势确定性。对于设备控制来说有时候“慢一点但稳定”比“快但不稳定”更好调试也确实更让人放心。6. 中断编程的“死规矩”这些坑我基本都踩过6.1 中断程序里不要做的几件事写中断程序和写主程序是完全不同的心态。主程序写得再乱最多是逻辑不好看中断程序里犯了忌轻则中断响应被拉长重则系统故障停机、数据错乱。不要在中断程序里调用通讯指令。无论是MODBUS读写、还是自由口发送通讯过程是有等待时间的而且常常以毫秒甚至几十毫秒计。你在中断里发起一个串口写操作CPU就要等发送缓冲区腾空这段时间里后续的中断程序全部被卡住相当于把“快速插队通道”变成了“慢速排队通道”。不要在中断程序里做长时间的循环或等待。有些PLC支持在中断里写FOR循环但你要清楚中断程序是在扫描周期中“插入”执行的它执行时间越长主程序被暂停的时间就越长。PID运算、滤波算法这类耗时运算放到主程序、或者放到定时中断的低优先级里去不要在硬件中断里做。不要在中断程序里调用一些“非中断安全”的系统指令。比如某些品牌的时钟读取、字符串拼接、文件读写操作看起来无害但在中断上下文中可能存在重入问题。最稳妥的做法是中断程序只做“置标志位、改几个变量、输出一个信号”这类最基础的操作复杂逻辑全部放到主程序的标志位轮询里。不要在同一个PLC里让大量中断同时频繁触发。如果一个CPU同时配置了多个中断源而且每个中断都是高频触发那CPU大部分时间都会在“进中断、出中断、再进中断”的切换中度过主程序几乎停摆。这时候优先考虑用高速计数器配合计数比较中断把多个脉冲合并成一次中断触发。6.2 中断与主程序的数据交接全局变量的“一致性陷阱”中断程序和主程序共享数据时存在一个隐蔽的坑数据一致性。举个例子。主程序在做一个多字节变量的计算读到一半时中断触发了中断程序修改了这个变量的某个字节。等主程序从中断返回继续读时它读到的可能是“改了一半”的数据——比如一个32位的计数高16位是新的、低16位是旧的。在主程序眼里这个数据就变成了一个不存在的“混合值”。解决这个问题的常用方案有几种中断程序只写、主程序只读数据和标志位方向固定避免同一变量被两边同时修改临时变量缓冲中断程序先写入一个临时变量主程序在读取处用一条“读取并锁定”指令有些PLC有MOV指令的原子性保证保证读到的是完整一致的值用双缓冲影子变量方案中断程序写的是“变量A”主程序用的是“变量B”主程序在非中断时刻把A拷贝到B但这要求拷贝过程不会被中断打断——通常搭配“禁止中断”指令来实现。我实际项目里的做法是第一种第二种组合所有中断源只负责往不同的全局变量里写值主程序统一在一个地方“快照”这些变量一次性拷到本地变量数组再基于快照做后续业务逻辑。这样主程序看到的数据始终是某个时间点上的一致状态不会出现“混搭”数据。6.3 中断触发的“抖动”场景一次误触发比不触发更麻烦前面已经提到过机械触点的灭弧问题这里再补充中断调试中的另一个常见场景信号抖动导致的多次触发。机械式断料检测杆、限位开关这类元件触点闭合时常常伴随多次抖动也就是短时间内反复通断。如果中断配置成上升沿触发那一次闭合可能被识别成两三次上升沿中断程序被执行多遍标志位可能被反复置位逻辑就乱了。解决的办法有几层硬件上用RC灭弧电路吸收电弧我之前就是这么做的软件上可以用“第一次触发后的禁止窗口”思路在中断程序里加一个时间锁定——比如触发后5毫秒内忽略后续触发这要用定时中断配合或者在中断里记录时间戳来做。如果PLC支持输入滤波设置优先通过参数来消化抖动比在程序里做时间锁定更可靠。还有一类“抖动”是来自编码器低速运行时的信号不稳定。编码器在极低速下输出信号容易变得忽长忽短如果中断程序在每一次边沿都做位置计算计算值可能不稳定。这种场景有两种思路一是使用正交计数模式用A/B相的关系判断真实位移方向减少误判二是不要基于边沿做位置而是基于高速计数器的锁存值在“达到设定值”中断时统一读取位置这样抖动的影响被平均掉了。7. 中断调试与排查的工具和方法不用示波器你就是在盲修7.1 我调试中断的三步流程信号源→响应链→程序内部中断出问题排查起来容易让人烦躁因为现象往往是“偶发触发”“有时快有时慢”“完全没反应”三类。我的调试流程是固定三步每一步解决一个层面的问题第一步确认硬件信号本身是干净的。用示波器至少是带波形显示的万用表测量中断输入端的信号看电平是否标准、是否存在抖动、脉冲宽度是否足够。这一步被很多人跳过直接改程序改完发现还是不行最后回到硬件才发现编码器线缆断了或者信号电平不对。一定要先确认硬件再谈软件。第二步确认响应链是通的。在中断程序的第一行先放一个“翻转输出点”的测试指令然后看对应的输出端子波形。如果接一个LED或者直接测输出能眼见着闪说明信号到达了CPU、中断被触发、程序被执行了这一整条链路是通的。如果这一步都不通问题就在中断配置或接线层面。第三步确认程序内部逻辑正确。链路通了之后再逐步加上真正的业务逻辑。加一点测一点防止一口气写完出问题时不知道是新加的逻辑还是原有逻辑的问题。7.2 常见问题速查表把这几个方向先过一遍我把这几年遇到的中断问题归纳成一个速查表调试时按表排查能省大量时间现象可能原因排查思路中断完全不触发输入点配置错误未设为中断模式接线错误滤波过大触发沿错误先测输入信号再确认配置再检查滤波参数最后确认触发沿中断偶发触发/多触发信号抖动滤波过小干扰耦合触点电弧示波器看信号抖动加RC灭弧调整滤波参数中断响应偏慢滤波过大中断程序过长全局中断被屏蔽CPU负载过高缩短中断程序调小滤波检查是否有DI禁止中断被意外触发主程序运行变慢中断触发频率过高中断程序里调用耗时指令使用分频/计数器匹配中断降低触发频率精简中断程序数据偶发错乱中断与主程序访问同一变量标志位未锁定采用影子变量/双缓冲逐层隔离多中断同时触发时逻辑错误中断优先级设置不正确共享变量被高优先级中断改写规划优先级隔离各中断的变量域必要时对共享变量加锁7.3 一个令我心有余悸的“低级错误”中断触发后程序再也回不来了这里要分享一个印象很深的案例。某设备改造我配了一个每2毫秒触发一次的定时中断中断程序里做编码器位置记录。调试时一切正常交付现场运行第二天设备偶发停机重启又好了。后来查出来问题出在我的一段测试代码没删干净——中断程序里有一行对某系列PLC而言不算“中断安全”的指令它在特定条件下会与中断机制冲突导致CPU在中断返回时异常。该PLC的CPU在检测到异常后自动停机并报错而重启后程序重新开始所以看起来像“偶发故障”。这件事给我的教训有三条现场调试时用的测试代码交付前必须逐个审查删除不要觉得“只是临时加两行”中断程序里的指令要对照手册确认“中断安全性”拿不准的宁可不写、挪到主程序交付前做至少24小时不间断的模拟运行比现场运行中发现问题后再补救要好得多。8. 最后的经验总结中断功能使用中我沉淀下来的几条心法中断功能在PLC编程中不难但要真正用好让它在现场稳定运行靠的是一次又一次踩坑之后沉淀下来的经验。最后分享几条我个人至今受用的心法。第一中断程序越短越好短到不能再短就是最佳状态。很多人写中断总是忍不住把功能做全但中断本身只负责“及时响应并记录现场状态”真正复杂的数据处理放到主程序里轮询处理这个边界划得越清晰系统越稳。我给自己定了一个不成文的规矩中断程序原则上不超过10行超过就重新设计。第二中断触发频率不是越快越好而是要“够用就行”。编码器1000线/转实际应用只需要每转触发一次中断做定位那就用匹配中断做一次而不是每脉冲都进中断。频繁的中断切换本身就是一种开销会消耗掉你原本想节省的CPU资源。第三交付前的抗干扰测试不能省。中断功能对干扰的敏感程度远高于普通输入输出。测试时把伺服、大电机、变频器都开起来人为制造启停冲击观察中断是否误触发。这一项做得越充分现场出问题的概率就越低。我之前遇到的大多数实际故障都和设备现场的干扰环境有关。第四把中断当成一个系统设计来做而不是一段程序。从传感器选型、接线方式、滤波配置、分频设置、程序写法到调试手段每一步都在影响最终的中断响应效果。任何一环掉链子中断都会从你的“精准武器”变成“随机故障发生器”。这篇文章基于我自己的项目经验把PLC中断功能从原理到接线、从配置到调试、从方法论到具体案例做了完整梳理。我不是在教你背接口而是在教你一种处理“实时性需求”的思维方式。希望你在看完之后下一次遇到“偶发问题”能有一个新的排查方向——先想想是不是该用中断了