资讯详情

资讯详情

PLC数据处理指令详解:从传送比较到移位转换的实战应用

直接进入正题。我见过不少刚开始搞PLC编程的朋友梯形图里画线圈、触点、自锁互锁一套一套的逻辑控制玩得飞起结果一到现场设备要跟仪表、变频器、上位机交换数据就卡住了。不是不会写程序是不知道面对一堆寄存器里的数字到底该用什么指令去挪、去算、去比。PLC的数据处理指令说白了就是干这个的。这篇文章我从实际干活的角度把传送、比较、算术、逻辑、移位、转换这几类最常用的数据处理指令掰开讲清楚什么时候用哪个、参数怎么填、现场容易在哪里翻车都会提到。适合刚从继电器思维转过来的电气工程师也适合做设备调试、跟HMI和上位机打交道的人。看完不敢说让你变成算法大师但至少面对一份需要处理数据的控制程序你不会再一头雾水。1. 只会“通断”是走不远的现代PLC的数据处理职责早就变味了很多教材喜欢把PLC定义为“可编程逻辑控制器”强调的是逻辑。但实际去了现场你会发现现代PLC早就不只是把输入信号搬到输出线圈那么简单的角色了。它的本质是一台工业级的嵌入式计算机CPU、内存、寄存器、通信接口一应俱全。之所以叫“逻辑控制器”那是因为历史习惯叫法真到了做项目的时候数据处理占的比重往往比想象中大得多。1.1 数据到底从哪里来又要到哪里去你想想一台稍微像样点的自动化设备里数据量一点都不少。称重仪表实时往PLC里灌重量值扫码枪把一长串字符结果发过来变频器回报当前运行频率和电流温度传感器模块把模拟量转成数字量塞进数据寄存器HMI屏幕要读写各种配方参数上位机还要从PLC里取产量数据做报表。这些场景没有一个是靠X触点和Y线圈能搞定的全部要落到寄存器上做数据的搬运和运算。我曾经接手过一条半自动包装线原来的程序很简单就是气缸到位、压紧、松开、计数几个逻辑动作。后来客户非要加一个在线称重分选需求称重仪表的数据得进PLC跟设定值比较再决定推杆动作。程序里面用于逻辑通断的部分没增加多少反而全是读数据、比较大小、做累计、写入显示的程序段。这个项目让我彻底意识到一件事PLC的数据处理指令才是真正支撑设备“智能化”的地基。1.2 逻辑控制与数据控制的边界在哪里简单说逻辑控制解决的是“什么时候做什么动作”数据控制解决的是“做了之后这个值怎么处理”。两者不是割裂的很多时候是同一个程序里配合使用。比如气缸推进这件小事需要判断限位信号是否为ON这是逻辑但气缸推到位之后要判断推力是否超过阈值推力值从变送器读进来跟设定值做比较这就是数据处理。所以初学PLC的朋友不要有误区觉得逻辑控制简单就先学数据处理难就放后面。数据处理指令本身一点都不难难的是理解数据在整个系统里的流转路径。你只要想清楚一件事——数据从哪个地址来、经过什么运算、最终写到哪个地址去——指令的选择就水到渠成。反过来说如果数据流转路线没搞清即使你把指令手册背得再熟到现场还是不知道怎么搭这个框架。2. 搬数据与做比较MOV、CMP这类指令才是使用频率最高的如果统计一下实际项目里所有程序指令的出现次数传送指令和比较指令绝对排在最前面。原因很简单任何数据处理的起点都是“把数据从一个地方搬到另一个地方”而所有决策动作的前提都是“现实数值与目标数值的比较结果”。2.1 MOV指令没你想的那么浅位长和地址类型都要盯紧很多人觉得MOV就是把一个值从源传送到目标简单得很。但实际用的时候有几个细节很容易被忽略。第一个是位长问题。大多数PLC的MOV处理的是16位数据也就是一个字。如果数据超过了16位能表示的范围就得用32位传送指令通常叫DMOV。曾经有人在程序里把一个32位的累积流量数据用MOV去传送结果高16位全丢了显示出来的数值一会儿对一会儿错排查了好久才发现是传送指令用错了位长。第二个是地址类型。MOV的源地址可以是立即数、数据寄存器、偶发是特殊功能寄存器目标地址一般就是数据寄存器。但要注意有些PLC对特殊功能寄存器是只读的你往里面传数值未必写不进去就算写进去也可能被系统强制刷新覆盖程序执行结果跟你想的完全不一样。这个在调试送电的时候特别容易踩坑最好在编程手册里把寄存器的读写属性先看明白。第三个是执行条件的配合。MOV放在条件为ON的扫描周期里执行意味着它会持续不断地传送数据。如果你只希望某个时刻传送一次那么条件必须是一个脉冲信号否则数据会被不断覆盖。不少初学者在这个问题上摔过跟头写了一个用常闭触点控制的传送结果目标数据不停跟着源数据变动整个程序逻辑都乱了。我用一个实际场景来说吧。设备上有两个配方A配方和B配方选哪个配方就把对应的一组参数搬进当前工作寄存器。这个场景就用两个常开的按钮输入分别触发两次MOV把不同配方区的数据一次性覆盖到工作区。这个用法简单但胜在清晰后面工艺参数修改都不用动逻辑只改数据区就行。2.2 CMP比较指令的三个标志位别只把结果当一个开关用比较指令CMP的功能是把两个数值做比较结果通过标志位反映出来。通常有三类结果大于、等于、小于。不同PLC标志位表示方式不一样有的用三个标志位分别对应三种结果有的用一个寄存器里的二进制位表示。我在这里想提醒的是比较指令虽然叫“比较”但它在程序里的用途远远超过“超限报警”这么简单。在实际项目中比较结果完全可以作为动作切换的依据。比如说称重分拣称出来的重量大于上限推杆推入A料箱等于或小于下限推入B料箱这本质上就是做了两次比较之后输出两路不同的动作。如果把比较结果单纯当成一个报警开关那数据处理就浪费了一半的能力。使用比较指令的时候还要注意数值格式的一致性。有些PLC比较器比较的是无符号数有些支持有符号数如果数据源里混入了BCD码格式的数值比较结果很容易出错。我的习惯是在比较之前先做一次明确的数据转换确保两个操作数的格式完全一致才进行比较。代码上看多了一行转换指令但调试的时候能为你省下大把时间。2.3 传送与比较的搭配逻辑排查问题的第一步永远是确认数据进来了没有程序里数据处理出了问题我总会告诉新手第一件事不是改指令而是确认数据源头是否正确。把这个原则落实成具体操作就是用监控模式去察看在线的寄存器数值。按下启动按钮那个对应的数据寄存器是否从0变成了1仪表发送过来的值是否已经出现在接收寄存器里如果数据根本没进PLC或者进到了你意想不到的地址后面一切比较、运算、输出都没有意义。传送指令在这里起到了“探针”的作用。我会在调试期间临时加一些MOV指令把关键中间值搬到一个专门用于监控的地址区域通过HMI或者编程软件的在线监视看一眼数值。确认无误后再把临时的探针删掉。这个习惯帮我快速定位过很多问题其效率远高于对着程序一行行猜。3. 加减乘除不只是算数算术运算指令里的数据类型与溢出陷阱算术运算指令的助记符大家都很熟悉ADD是加法、SUB是减法、MUL是乘法、DIV是除法。但真正在现场调试的时候出问题最多的恰恰是这些看起来人畜无害的“算数”。问题根因就两个数据类型不匹配、运算结果溢出。3.1 16位运算的边界问题比你想的更容易触发我们先来算一笔账。16位有符号整数的范围是-32768到32767无符号的是0到65535。在工业现场一个比较大的计数数值、一个累积流量稍微运行一阵子就可能突破这个范围。一旦运算结果溢出程序不一定会报警但寄存器的值会突然变成一个莫名其妙的负数或者很小的正数跟现实完全对不上。解决方式是使用32位运算指令或者在做乘法和加法之前先把16位数据扩展成32位再参与运算。千万别以为只有做乘除才需要32位哪怕只是一个简单的加法两个数都是两万多加起来就可能突破32767了。现场的实际值如果接近临界范围宁可提前换成32位运算也不要等出了故障再去猜。我记得有个项目是做板材计数一个班的产量累计在十几万片一开始程序用16位加法累加运行到半上午数据就乱了显示成负值还继续加。后来改成32位累加问题立刻消失。这个案例听起来特别基础但在现场就是经常发生原因就是写程序的时候没把量程算进去。3.2 除法的商和余数别把余数当垃圾丢了DIV除法指令执行完之后不仅仅产生商还有一个余数。大多数PLC把商保存在目标寄存器里把余数放在紧挨着的下一个寄存器中。有人只关心商而忽略余数结果在后续处理里需要用到余数来分析和计算的时候发现那个位置的数据早就被别的指令覆盖了。余数在一些场景下是有实际意义的比如做分度计算、位置换算、圆周分割。举个例子一个转盘上均匀分布12个工位你有一个绝对角度值想知道当前停在第几个工位就可以用角度除以360再除以每个工位角度商是转过的圈数余数决定工位号。这种算法虽然也可以用其他方式实现但用DIV拿余数是很自然的一条路。所以我建议写除法运算时如果不确定后续逻辑会不会用上余数干脆把商和余数的寄存器都预留出来贴上注释说明。即使当前用不上也给后续维护留一条后路。3.3 浮点数运算在PLC里的正确打开方式传统的整数运算在需要高精度的场合远远不够用比如温度值25.6摄氏度、压力值1.25MPa、实物重量12.345千克。现代PLC普遍支持浮点数运算但在PLC里浮点数和上位机程序里的概念没有本质区别都遵守类似IEEE754的存储格式。实操中有两个常见的坑。第一个是整数和浮点数的混用很多PLC的运算指令并不自动做隐式类型转换你必须先通过转换指令把整数转成浮点数再参与浮点运算否则轻则精度丢失重则直接报错。第二个是浮点数在显示的时候要注意精度格式比如在HMI上明明PLC里存的是25.60000显示出来却变成了25.59999这不是数据错了而是浮点数二进制存储固有的精度现象。如果你在意这个处理方法一般是在HMI显示端做位数截取或者在PLC端把浮点数放大为整数后再显示。浮点运算对我个人来说用得最多的场景是PID控制的前置处理比如把模拟量输入换算成工程单位或者把工程单位再反算成输出占空比。这些公式不复杂但类型转换搞错了整个控制环就废了。所以我养成了一个习惯凡是写浮点运算程序第一行永远是类型转换指令先把输入量统一成浮点格式再往下算。3.4 逻辑运算不只是“与或非”它还能干位掩码的活儿逻辑运算指令比如AND、OR、XOR在PLC里往往被看作非常初级的东西因为继电器逻辑电路里就有与或非。但在数据处理这个语境下逻辑运算的用途是把一个数据里的某几位截取出来或者把某几位单独赋值为0或1这就是业内常说的按位处理。举个例子一个状态寄存器里第0位表示运行状态第1位表示故障状态第2位表示手动模式。你想单独提取故障状态就可以用寄存器和一个常数做与运算这个常数第1位是1其他位是0这样就可以把第1位的值单独“抠”出来。这种技巧在跟变频器、伺服驱动器、通信模块打交道的时候几乎天天用。用生活化的类比逻辑运算里的与运算就像一套筛子你设置好哪一位要透过筛子哪一位被挡住结果里就只保留你关心的那几位。这个思路比照着位的定义一条条写IF判断要高效得多。4. 移位、循环与转换指令现场高级玩法的底层支撑如果说前面传送、比较、算术是基础款那么移位指令、循环指令、数据转换指令就是拉开程序水平差距的分水岭。很多人在书本上见过这些指令但实际项目里用不上就没认真学。真实情况恰恰相反越是自动化程度高的设备越离不开这类指令。4.1 移位指令解决流水线工位跟踪比一堆中间继电器优雅太多在流水线式的设备上产品沿传送带依次经过各个工位每个工位有不同的加工动作。难点在于如何知道传送带当前哪些位置上有产品每个产品应该在哪个工位做哪种动作。传统的做法是用一组中间继电器去模拟位置状态但产品多了、工位多了这种继电器做法会变成一场灾难。移位指令天生就是解决这个问题的。简单讲你用一个16位的数据寄存器表示传送带上的16个位置寄存器某一位是1就代表对应位置有产品。每当传送带前进一个固定间距就把这个寄存器整体向左或向右移动一位同时在寄存器入口处写入新产品的有无状态。这样整个传送带上的产品分布状态就被一个寄存器完整刻画出来了。这个场景我做过多回印象最深的是一条装盒线产品经过封箱机之后要分流到三条包装支线。我用一个字的移位寄存器跟踪进料位置用三个比较指令去判断不同位置上的产品应该去哪条支线。程序结构非常清爽现场维护的人也很容易理解。如果用传统继电器方案十几个继电器加几十条逻辑才能实现同样效果。移位指令的使用关键在于“移动一位”与“物理位置变化一个节距”必须严格对应。所以在编写这类程序时移位指令通常不是持续执行而是在检测到传送带编码器转过一定角度时由脉冲信号触发执行一次。如果触发条件设计得不好位置信息就会逐渐错位堆出来的货比预料的多一个或者少一个排查起来特别痛苦。4.2 循环移位指令做旋转工位逻辑省心省力循环移位指令跟普通移位类似唯一区别是把从一端挤出去的那一位补到另一端形成一个循环。这个名字听上去很抽象但应用场景特别明确——圆盘式多工位设备。假设一个8工位的旋转工作台每个工位依次经历上料、检测、加工、下料等工艺。工件的实际位置是随着转盘旋转而复用的下一个周期的工件又会回到第一个工位。这个时候如果用普通移位指令数据总有一天会被移到寄存器外面丢失掉。循环移位指令则完美适配这个逻辑转一圈、位循环一圈状态刚好对得上。我见过有人用一长串的加减计算和条件判断来实现旋转工位跟踪程序写了三屏之多调试的时候自己都绕晕了。而用循环移位指令加上每转一个工位触发一次移位几行代码就能把事情说清楚。数据处理的精髓往往是选对了指令代码自然就变短了。4.3 BIN/BCD转换指令跟仪表和显示设备打交道绕不开的格式障碍许多传感器仪表为了方便读数输出的是BCD码格式的数据。所谓BCD码就是把一个十进制数的每一位分别用一组二进制去表示它是一种“四位的二进制数对应一位十进制数”的编码。学过的人清楚用起来其实很别扭因为PLC内部的算术运算并不支持BCD码你必须先转换成普通的二进制数BIN格式做完运算后再转回BCD格式送给显示设备。这个转换指令在跟称重仪表、温度控制器、计数器模块通信时几乎避不开。我第一次接触的时候吃过亏从仪表读回来的重量值直接送到HMI显示结果屏幕上显示出一串奇怪的十六进制数字完全不是正常的重量。后来才弄明白仪表默认输出的数据格式是BCD而HMI按二进制格式去解读了。处理这种问题的经验是先搞清楚通信协议的格式定义明确各个寄存器输出的到底是BIN还是BCD再决定是否需要加转换指令。不要不加判断地直接搬数据格式错了数值再对也是白搭。另外上位机或HMI在读写PLC数据时同样存在格式一致性问题你在PLC里辛辛苦苦转换好的数值到了上位机如果没有按约定的格式解析还是会乱。所以数据格式这件事需要整个系统从上到下采取统一约定不能只盯着一处。5. 一个真实项目里的数据流从称重仪表到分流推杆数据经历了什么理论讲了不少拿个实际案例把数据流的完整链路串起来讲效果会好很多。我之前做过一条产品分选线客户要求根据产品重量分成三个档位然后由不同的推杆把产品推入对应料箱。这个项目的核心就是数据处理没有复杂的动作逻辑但每一步数据变换都必须正确。5.1 需求拆解与数据链路设计先理清需求。产品经过称重台仪表把重量值发给PLCPLC将这个值与上下限比较比较结果决定推杆的动作。此外还需要统计每个档位的产品数量并在HMI上实时显示当前重量和累计数量。我把数据链路画出来是这样的称重仪表通过通信将重量值存入PLC指定寄存器BCD格式。通过转换指令把BCD格式转换成BIN格式放入中间寄存器。将BIN格式重量值乘以一个倍率系数得到以克为单位的实际重量。实际重量与两个设定值做比较比较结果驱动三个档位的推杆输出。每次比较完成对应档位的计数值加1。HMI从PLC读取重量、计数值、设定值用于显示和参数修改。这里面每一步指令的选择都很明确而且我特别重视格式转换这一步。因为仪表输出的BCD码如果不做处理加法、比较都无从谈起所以转换指令放在数据链路最前端一定不能漏。5.2 核心程序怎么写才能避免重复累加分档计数这个环节比较容易犯的错误是只要推杆还在动作期间计数指令的扫描条件一直为ON计数就不断重复增加一次合格品被记录成十几次。解决方式有几种我习惯用比较结果从0变1的上升沿脉冲去触发累加。用指令表的写法思路大致是这样把重量比较结果存储在一个辅助寄存器里。如果这一档的比较结果刚变为ON且前一周期该结果还是OFF则触发一次加法指令给计数值加1。这样无论推杆动作持续多长一个产品只对应一次累加。当时程序里最难调的就是这个脉冲触发的部分。因为在梯形图里写上升沿脉冲不同品牌的PLC触点写法不同但思路是一致的需要“当前周期状态”和“上一周期状态”两个位一起判断。现在很多PLC自带上升沿触点直接用就行。5.3 边界情况和信号抖动怎么处理工业现场没有理想数据。称重产品经过秤台时数值会跳动特别是传送带还在运行的情况下产品还没完全停稳重量值已经开始往上冒了。如果程序不加任何处理可能取到一个偏大或偏小的瞬时值分选结果就会出错。我当时加了一个简单的稳定判断当重量值连续若干次采样变化幅度小于一个阈值时才认定重量稳定允许进入下一步比较。这个实现用到了比较指令和计数器逻辑上不复杂关键是阈值和时间窗口的选择需要根据现场动态调。这个经验后来在很多项目里都复用上了我个人觉得比直接买贵的仪表值当“稳定”要靠谱得多因为现场振动、电磁干扰都会让瞬时值变得不靠谱。另外档位设定值、倍率系数这些参数我全部放在了HMI可写的寄存器区而不是写死在程序里。这样客户需要调整分选范围时直接在触摸屏上改就行不用打开电脑改程序下装。5.4 项目做完之后的几句实在话这个项目本身不复杂但它是典型的数据处理完整闭环。仪表数据进来、格式转换、运算比较、结果输出、统计累加、显示交互一条线全部打通。做完之后我感觉最能提高调试效率的就是在动手写程序之前先把数据流向图画清楚。当时我在纸上把每个数据的源地址、目标地址、数据类型、转换步骤都标出来然后才开始写逻辑。实际操作中这个准备工作花了大半个小时但后面的编码和调试非常顺利。对比以前摸着石头过河的状态这个习惯帮我省下的时间远超过那半小时。6. 数据被“吞了”从三类真实故障看数据处理指令的调试基本功无论指令学得多熟到了现场总会遇到程序结果跟预期不一致的情况。我总结遇到最多的故障大致有三种每个背后都有一套固定的排查链路分享出来希望对大家有实际帮助。6.1 监控有值但程序不动作先查执行条件再查数据声明遇到过这样一个情况数据明明已经在寄存器里了但程序就是不执行相应的动作。程序里面有一行ADD指令负责把一个增加的数值累加到总量寄存器里可不管怎么加减操作总量纹丝不动。我的排查思路是先在线监视程序看ADD指令前面的条件触点是ON还是OFF。结果发现条件触点在绝大部分时间都是OFF只在按下按钮的那一瞬间是ON。但ADD指令本身不是脉冲执行而按钮按下的时间又短条件ON的时间只有一个扫描周期的一部分却执行了一次或多次理论上不该完全没变化。继续深挖原来问题出在这个条件触点被其他地方的一个双线圈冲突影响某个分支程序在某个时刻把同一个输出位强制写成了OFF覆盖了按钮输入的ON信号。这种双线圈问题靠眼睛盯很难发现用程序的交叉引用功能查找这个位在哪些地方出现很快就找到问题位置了。这给我一个很重要的启发遇到数据处理结果不对时不要急着怀疑指令参数优先检查这个指令执行的条件是否稳定成立。很多时候不是“算法不对”而是“该执行的时候没执行”。6.2 数值乱跳甚至出现负数检查数据格式和转换步骤另一个常见故障是从模拟量输入模块读回来的温度值在HMI上显示的时候一会儿是25.3一会儿又变成-12.7特别不稳定。如果模拟量模块和PLC之间的数据类型、数值范围没弄对很容易出现这种奇怪的显示。排查链路是这样先用编程软件在线监视模拟量通道的原始数值寄存器看是一个什么样的数据范围。如果原始数值在0到4000之间变动基本说明模拟量模块的采集本身没问题。接着检查PLC里做的量程换算公式看看是把0到4000的原始值换算成工程单位还是漏了某个系数。我当时发现那个温控模块的原始数据是0到4000对应-50到200摄氏度而程序里的换算公式却按0到10000的量程去做比例计算算出来的结果当然完全不对浮点部分还会因为符号转换问题变成负值。把量程系数改过来后显示立刻恢复正常。这里我特别强调一下不同厂家的模拟量模块其数字量范围差异很大有的0到4000有的0到20000有的带符号有的无符号。拿到新模块的第一件事就是去手册里查模拟量数值范围和对应的工程单位不要凭经验猜猜错的概率比想象中大得多。6.3 数据能进但读出来不对通信字节顺序和地址偏移是重灾区跟外部设备通过通信交换数据时还有一种看似“没毛病”的故障数据明明已经从设备发过来了PLC寄存器里也能看到一组数据但数字组合起来就是不对。最典型的就是字节顺序搞反了。很多智能仪表在通信时默认发送的是高字节在前、低字节在后但PLC内部的寄存器是低字节在前、高字节在后。如果不做字节交换处理你读到的数据看起来就是一组对调过的乱码比如实际的0x1234读出来变成了0x3412。排查这个问题的方法很直白通信调试窗口里看十六进制的原始报文同时对比PLC寄存器里接收到的数据。把两者摆在一起如果高字节和低字节位置对不上那就是字节序问题加一个字节交换指令即可。这类问题如果你没预料到排查起来会觉得非常玄学但知道了原因之后一分钟就能解决。还有一个地址偏移的问题有些设备说明书写第1个数据地址是40001但在PLC实际映射里却是40010中间隔了9个空地址。很多人在这个偏移量上翻过车数据读回来总是在某个区段错位。遇到这种情况我一般会从设备文档上把寄存器地址表完整抄下来跟PLC通信配置里的地址逐个核对一遍确认没有偏移误差再进行通信调试。6.4 调试工具与习惯比记住所有指令更值钱说到最后我觉得调试数据处理程序最值钱的工具不是某条高级指令而是在线监视功能的使用熟练度。一个合格的工程师应该做到看到程序里任何一个关键数据寄存器能立刻在监控窗口里把它找出来能看懂数值的单位和含义。这项能力需要平时多加练习没有什么捷径。我自己的习惯是在每一段数据处理逻辑旁边都加上详细注释数据源是什么目标是什么单位是什么转换公式是什么。现场出故障时照着注释一步步查效率非常高。如果程序里全是裸奔的数字没有注释过三个月再看就完全不认识这些寄存器是干什么用的了更别说调试。还在做PLC这行的朋友如果手头有旧项目的程序不妨把里面所有用过数据处理指令的段翻出来复盘一下。看看当初的注释全不全想想现在会用什么不同的思路实现。技术这件事就是要靠一个个实际项目的积累和反刍才真正变成自己的本事。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →