欧姆龙NX系列PLC:ST语言与梯形图混合编程实战解析

发布时间:2026/10/10 14:30:09
欧姆龙NX系列PLC:ST语言与梯形图混合编程实战解析 1. 项目背景与设计思路ST和梯形图为什么要混用1.1 别一根筋NX系列不是只能画梯形图的PLC做过欧姆龙NX系列的朋友应该都有同感这代PLC早就不是以前那个只能画梯形图的PLC了。Sysmac Studio里既能拖梯形图又能写ST、C甚至还能把整个运动控制、视觉、机器人全部塞进一个工程里。但很多从旧时代转过来的老工程师拿到NX第一个动作还是打开梯形图往里面堆触点、线圈、定时器最后搞出几百个IL、IN、Q、定时器编号程序翻三页都找不到一个输出。我自己刚开始接触NJ/NX的时候也走过这个弯路。后来被一个用ST写数据处理的老同事点了一下你那些几百行的梯形图其实一大半是在做数学运算、数据搬移、通信解析这些东西用梯形图写又难读又难改。从那以后我形成了自己的习惯逻辑控制用梯形图数据处理用ST。这个标题里的“ST语言和梯形图配合使用”本质上就是这句话。NX系列CPU本身支持IEC 61131-3标准在Sysmac Studio里可以同时建立多个POUProgram Organization Unit每个POU可以独立选择编程语言。同一个项目里主程序用梯形图功能块用ST这完全没有问题。系统会自动分配任务周期把不同POU挂到同一个Task下按顺序执行。所以混用不是“硬凑”而是平台本来就给你留好的路。1.2 先搞清楚POU、任务和变量这三个基础概念要混合编程首先得把NX的项目结构看明白。Sysmac Studio里最常见的POU类型有三种Program程序相当于传统PLC里的主程序或子程序有独立的任务周期可以调用其他POU。一个项目里可以有多个Program每个Program分配到一个Task下。Function Block功能块带静态变量也就是调用一次之后内部数据会保留。最适合做滤波、PID、状态机这类需要“记忆”的算法。Function功能不带静态变量像数学函数一样无记忆。比如单位换算、字节拼接适合做纯计算的工具函数。然后把POU挂到Task里。NX的任务分优先级默认有周期性任务。比如把主Program放在Primary Periodic Task里周期设为1ms或2ms所有运动控制、报警扫描都在这个节拍下执行。数据处理类的功能块我通常也放在同一个Task里保证数据进出是同步的。如果有一些慢速的通信协议处理我才会单独建一个低优先级的任务比如10ms或50ms跑一次。变量方面Sysmac Studio不再有传统的“地址表”概念而是直接声明变量名。全局变量在Global Variables表里定义可以跨POU访问局部变量在POU内部定义外部看不见。混合编程时梯形图和ST之间的数据交换就是靠全局变量和功能块引脚输入输出参数连接的。1.3 一个典型的“梯形图逻辑 ST数据”架构拿我最近做的数控机床数据采集项目举例。整个NX控制柜既要控制整机的按钮、指示灯、液压阀、冷却泵又要采集几十路模拟量传感器信号还要通过Modbus TCP把数据上传给上位机。如果全用梯形图写模拟量滤波、工程值转换、数据打包那部分会占掉一半以上扫描时间而且你想改一个滤波系数得翻梯形图翻半天。所以我把它拆成了两半梯形图部分设备启停、按钮互锁、液压顺序、报警灯输出。这部分用梯形图画出来电工师傅看一眼就懂现场调试也好沟通。里面会放置ST功能块的调用框。ST功能块部分模拟量滤波、温度计算、压力报警判断、Modbus保持寄存器数据打包、OPC UA变量映射。全部用ST写成独立功能块梯形图里“调”它们就可以了。这样拆完之后整个程序结构变得很干净。上位机、触摸屏那边需要什么数据我就从ST功能块的输出引脚或全局变量里直接取不用再去梯形图里翻来覆去地找继电器位。2. 数据与逻辑分离的具体设计2.1 变量规划先起好名字再写一行代码混用ST和梯形图最容易踩的坑就是变量命名乱。梯形图习惯用I:0.0这种地址但NX是用变量名。如果我们这边叫Motor_Start那边叫m_start功能块里叫start_cmd短时间内没问题项目一大了梯形图连线直接乱套。我的建议是定一套前缀规范全局统一BOOL变量前缀b比如bStartCmd、bAlarmReset整数变量前缀n或i比如nStep、nChannel实数变量前缀r比如rTempPV、rPressureRaw数组变量前缀arr比如arrBuffer[0..15] REAL结构体变量前缀st比如stAxis、stAlarm这样在梯形图里看到bStartCmd就知道是一个BOOL指令在ST里看到rTempPV就知道是温度过程值不用来回查定义。尤其是梯形图的功能块调用框里输入引脚和输出引脚是列表排列的如果名字本身清晰绑线的时候几乎不会出错。另外我强烈建议在全局变量区建立几个结构体数组。比如采集16路温度传感器就建一个stTempSensor[0..15]结构体里面包含TYPE stTempSensor : STRUCT rRaw : REAL; // AD原始值 rEngineering : REAL; // 工程值单位℃ rUpperLimit : REAL; // 报警上限 rLowerLimit : REAL; // 报警下限 bAlarmHigh : BOOL; // 上限报警 bAlarmLow : BOOL; // 下限报警 bConnected : BOOL; // 通道故障 END_STRUCT END_TYPE这样一来ST功能块处理数据时可以直接按序号循环梯形图里做报警逻辑时也能直接取stTempSensor[0].bAlarmHigh这样的变量。数据归数据逻辑归逻辑两者交叉点只有一个结构体维护起来很舒服。2.2 ST语言处理数据滤波、转换、字节解析三板斧ST最舒服的场景就是批量数据处理。我用得最多的是三个套路基本上每个项目都能用上。第一是滤波。模拟量现场都有噪声直接拿原始值去触发报警报警点会反复抖动。我一般用一阶惯性滤波ST代码很短FUNCTION_BLOCK FB_AnalogFilter VAR_INPUT bExecute : BOOL; // 每个扫描周期调用一次 rRawValue : REAL; // 采集到的原始工程值 END_VAR VAR_OUTPUT rFiltered : REAL; // 滤波后的输出值 END_VAR VAR rPrev : REAL; // 上一次输出 rAlpha : REAL : 0.2; // 滤波系数越小越平滑 END_VAR IF bExecute THEN rFiltered : rAlpha * rRawValue (1.0 - rAlpha) * rPrev; rPrev : rFiltered; END_IF;这个功能块的好处是梯形图里每一次扫描调用一次FB_AnalogFilter实例输入接当前读到的原始值输出直接给到HMI显示。想改平滑程度只需要改rAlpha。比在梯形图里用比较器、定时器搭一整套去抖逻辑痛快得多。第二是工程量转换。传感器输出4-20mAPLC读进来是0-27648或者0-4096看配置但上位机要的是0-100℃。这种线性映射ST里一句话就完成rEngineering : (rRaw - nRawMin) / (nRawMax - nRawMin) * (rEuMax - rEuMin) rEuMin;我一般把这个做成一个Function输入原始值和量程范围输出工程值。因为它是无记忆的所以不需要功能块普通的Function就够。梯形图里想算任何一路通道的量程转换直接调用这个自定义功能输入引脚绑上变量就行。第三是通信数据解析。NX做Modbus TCP或OPC UA的时候接收缓冲区往往是ARRAY OF BYTE。上位机或第三方设备发过来的数据经常是两个字节拼一个Word或者一个Word里某一位代表某一个状态。这种解析如果放梯形图里移位指令、与指令写出来一堆看起来像天书。用ST就直观得多// 把第0号和第1号字节拼成一个16位整数按大端模式 nTempWord : SHL(INT_TO_WORD(arrBuffer[0]), 8) OR WORD_TO_INT(arrBuffer[1]); // 取第3位作为故障标志 bFault : (WORD_TO_BOOL(INT_TO_WORD(nStatusWord) AND WORD#16#0008));当然ST也不只是能做这些。数组排序、批量移动数据、CRC校验、PID运算、轨迹规划预计算都适合用ST写。核心原则是凡是“算”的活都往ST放。2.3 梯形图实现逻辑互锁、顺序控制、报警输出那ST是不是万能也不是。至少设备启停逻辑、安全互锁、急停链、手动自动切换这些我坚持用梯形图。原因很简单梯形图是“看得见电路”的语言。按钮一按接触器吸合互锁触点断开电气维修的人不用懂ST也能看懂。如果这些主回路逻辑也写进ST现场电气调试时人家拿万用表量完端子跑来说“我要看这个线圈为啥没吸”你总不能甩给他一个IF语句阵列。梯形图里做逻辑有几个好用的习惯互锁逻辑直接用常闭触点。比如正转接触器和反转接触器梯形图里把对方的常闭触点串联进来这比ST里写死条件更直观而且电工师傅修改起来不需要动PLC程序逻辑结构。顺序控制用INT步号变量。我习惯用一个全局变量nStep代表当前工艺步骤。梯形图里每步用一个比较触点判断当前步号然后驱动这步的输出线圈。这样整个工艺流程清清楚楚每一步是什么动作一目了然。报警逻辑单独放一段。报警数据来自ST功能块输出的BOOL变量梯形图只需要把这些BOOL变量串联到报警输出线圈或触发蜂鸣器、故障灯。报警延不延时、需不需要锁存都可以在梯形图里用定时器、辅助继电器实现。这样的划分等于把“大脑”和“肌肉”分开。ST负责思考数据梯形图负责执行动作。NX扫描时先执行ST功能块刷新所有计算结果再执行梯形图逻辑输出到物理端子。逻辑不混乱数据也不迟到。2.4 交互接口功能块引脚怎么和梯形图配合ST功能块写好了最终要在梯形图里落地。Sysmac Studio的梯形图编辑器里可以直接插入一个功能块调用框像放置一个线圈或指令一样。它会列出所有VAR_INPUT和VAR_OUTPUT引脚你只要把全局变量绑定到引脚上。这里有一个关键习惯功能块内部不要用全局变量全部通过引脚输入输出。如果功能块内部直接读了全局变量那这个功能块的复用性就废了。你写了一个滤波功能块下次换一个项目还得去改里面的全局变量名碰线碰得想哭。正确的做法是FUNCTION_BLOCK FB_ScaleConverter VAR_INPUT rValue : REAL; rMinRaw : REAL; rMaxRaw : REAL; rMinEu : REAL; rMaxEu : REAL; END_VAR VAR_OUTPUT rScaled : REAL; END_VAR IF (rMaxRaw - rMinRaw) 0.0 THEN rScaled : (rValue - rMinRaw) / (rMaxRaw - rMinRaw) * (rMaxEu - rMinEu) rMinEu; ELSE rScaled : rMinEu; END_IF;在梯形图里调用时只要把rValue绑到当前通道的实时值把量程上下限绑到HMI里设定的变量上输出绑到stTempSensor[0].rEngineering。这样一个功能块16个通道就实例化16次每个实例引脚绑不同变量。梯形图看起来就是一个个整齐的功能块框语义非常清楚。3. 实操过程用Sysmac Studio搭建一个混合编程实例3.1 创建工程和配置NXCPU我用的是Sysmac Studio版本目前比较常见的是1.30到1.50左右。新建工程时选择设备类型为NX具体型号看你手里的CPU比如NX1P2或NX701。这里要注意一个细节创建工程时尽量把单元版本选到当前支持的最高版本否则部分功能块和指令可能不可用。当然也不能选得比固件高否则下载程序时会报版本不匹配。建完工程后第一件事是在“配置和设置”里把EtherCAT轴、模拟量模块、通信板卡都添加进去。NX和NJ一样模拟量输入模块要在I/O映射里关联变量这样才能在程序里读取原始值。我会在I/O映射表里把每个通道的输入原始值映射到全局变量比如arrAIValue[0]、arrAIValue[1]数据类型通常是INT或WORD。然后设置任务周期。如果项目里用了伺服我一般把Primary Periodic Task周期设为1ms保证运动控制刷新率如果只是普通逻辑和模拟量2ms或者5ms也够。ST功能块没有特殊周期要求只要挂在这个任务下它会跟随任务周期性执行。注意ST功能块的执行时间必须控制在任务周期之内否则会影响整个任务的实时性。这是后话但必须提前想好。3.2 编写ST功能块一个完整的温度和压力处理实例我在这里写一个简单的ST功能块组合方便你理解整个流程。假设有8路PT100温度通道我们要做滤波、工程量转换、上限报警判断。首先建一个全局结构体数组stTempSensor[0..7]然后在“POU”里新建一个Function Block语言选ST名字叫FB_TempProcess。代码逻辑是这样的FUNCTION_BLOCK FB_TempProcess VAR_INPUT bExecute : BOOL; rRawValue : REAL; // 0-27648原始值 rRangeMin : REAL : -50.0; // 量程下限℃ rRangeMax : REAL : 150.0; // 量程上限℃ rFilterCoef : REAL : 0.15; // 滤波系数 END_VAR VAR_OUTPUT rTemperature : REAL; // 滤波后工程值 bAlarmHigh : BOOL; bAlarmLow : BOOL; bSensorFault : BOOL; // 断线或超量程 END_VAR VAR rPrev : REAL; END_VAR IF NOT bExecute THEN RETURN; END_IF; // 1. 工程值转换 IF rRawValue 0.0 AND rRawValue 27648.0 THEN rTemperature : (rRawValue / 27648.0) * (rRangeMax - rRangeMin) rRangeMin; ELSE bSensorFault : TRUE; RETURN; END_IF; // 2. 一阶滤波 rTemperature : rFilterCoef * rTemperature (1.0 - rFilterCoef) * rPrev; rPrev : rTemperature; // 3. 报警判断 bAlarmHigh : rTemperature rRangeMax * 0.95; bAlarmLow : rTemperature rRangeMin * 0.95;这个功能块输入输出全部是引脚梯形图里每路通道实例化一个然后把各自的原始值、量程上下限和滤波系数绑进去。这样不会有一大堆重复的ST代码堆在主程序里梯形图也只看到一行行功能块。3.3 编写梯形图主程序并调用功能块梯形图主程序里第一步是一段启停逻辑和急停逻辑产生bRun、bReduce这些运行标志。第二步就是数据处理区。我在梯形图里插入8个FB_TempProcess实例每个实例对应一个通道。比如第0个通道bExecute直接连一个常ON标志我用系统自带的P_On。rRawValue连到I/O映射变量arrAIValue[0]转换后的REAL变量。rRangeMin连到HMI设定变量rHmiTempMin[0]。rRangeMax连到rHmiTempMax[0]。rFilterCoef连到rHmiFilterCoef[0]。rTemperature输出到stTempSensor[0].rEngineering。bAlarmHigh输出到stTempSensor[0].bAlarmHigh。这样一来梯形图里就是8个整整齐齐的功能块框电气同事看了也知道每个功能块是干什么的。ST里复杂的滤波、转换、报警判断全部封装在功能块内部梯形图不背这些锅。第三步是逻辑控制区比如冷却泵启动条件手动时按按钮自动时看温度是否超过60℃还要看冷却泵接触器反馈信号有没有到位。这段直接用梯形图常开常闭触点搭。报警输出区把stTempSensor[0].bAlarmHigh这些BOOL直接并联到故障灯线圈。3.4 编译、仿真与在线调试写完以后点编译。Sysmac Studio会检查所有引脚的变量绑定和类型匹配。第一次编译通常会有很多错误大多数是数据类型不匹配或者引脚未连接。比如你REAL引脚绑了一个INT变量编译器就会报类型错误。这种错误在ST和梯形图混合的工程里特别常见因为梯形图连线的时候很容易随手拖一个INT变量到REAL引脚上。解决方法是显式转换要么在ST功能块里把输入参数定义成INT要么用INT_TO_REAL转换指令包一层。我习惯是把所有模拟量原始值都转成REAL再传给ST功能块这样功能块内部不用处理整数类型通用性更强。仿真调试时Sysmac Studio有模拟器模式可以强制输入变量观察ST功能块内部变量。这块特别有用你可以把rRawValue强制成27648看rTemperature是不是100℃看报警有没有翻。确认数据逻辑没有问题再下载到真实PLC。在线调试时我最常用的是“数据监视器”同时监视梯形图里的线圈状态和ST功能块内部的rPrev、rFiltered。如果发现温度波动很大直接在线改rFilterCoef观察实时曲线。这里要注意在线改常量或变量值Sysmac Studio是可以直接写的但改完记得要做一次“变更”下载否则断电后又会恢复原值。我吃过这个亏改了一下午滤波参数结果断电重启全回去了。4. 常见问题与排查技巧实录4.1 数据类型不匹配REAL、INT、WORD搅成一锅粥ST语言对数据类型要求比梯形图严格得多。梯形图里你把一个INT变量直接串进比较指令系统还能自动容忍但在ST里INT和REAL参与运算基本都会报错。我见过最多的问题是把ADC模块读到的INT原始值直接传到ST功能块的REAL输入引脚。在ST里做位运算时把INT和WORD混用导致SHL、ROL这类指令报类型错误。函数块返回的BOOL接到梯形图线圈时把BOOL变量接到W变量上或者反过来。我的排查经验是编译错误先看第一个不要看后面的。Sysmac Studio经常因为第一个类型错误连带报出一串引脚不匹配的错。把第一个解决了后面很多会跟着消失。4.2 ST内部的循环别让扫描周期爆炸ST里写FOR循环很爽但要注意循环次数。NX CPU指令执行速度很快但如果循环里还调用了其他功能块或者循环次数达到几万次就会拖垮任务周期。有一次我做数组排序用了三层嵌套FOR循环数据量是几百个元素结果Primary Periodic Task的扫描周期从1ms直接变成十几毫秒伺服一运行就报同步错误。后来我把排序算法改成每周期只排一段循环量分散到多个扫描周期执行或者把排序放到一个低优先级任务里才把周期压回去。所以我的原则是实时任务里的ST循环单次循环次数控制在几十次以内大批量数据处理要么分周期要么放到慢速任务要么直接用支持循环缓冲区的通信指令。否则功能没坏设备已经被你搞爬窝了。4.3 梯形图和ST的可见性与执行顺序问题梯形图里能访问全局变量也能访问POU内部局部变量吗答案是不能。梯形图Program只能访问全局变量和本POU内的局部变量不能直接摸到另一个功能块内部的局部变量。所以如果你在ST功能块里定义了一个中间变量rTemp想在梯形图里直接看这个值做判断是看不到的。你需要把rTemp暴露成输出引脚或者在全局变量表里再映射一份。执行顺序也是一样。同一个Task下的多个POU是按顺序执行的。如果你的梯形图逻辑用了某个ST功能块的输出那这个ST功能块必须在梯形图POU之前执行。我一般把数据处理功能块放在一个单独的POU里并且把这个POU放在梯形图POU前面。Sysmac Studio里可以通过拖拽任务下的POU顺序来调整别小看这个顺序顺序反了就是“上一周期数据下周期逻辑”的经典问题。4.4 通信数据解析的字节序和故障值问题做Modbus TCP或OPC UA读取传感器、数控机床、上位机数据时ST解析字节数组要特别注意字节序。欧姆龙NX默认很多通讯协议是大端在前但一些国产仪表可能是小端。我曾经遇到过一台温控器把16位温度值的高低字节反着发ST代码解析出来温度零下几十度折腾了俩小时才反应过来是字节序问题。另外通信线断了之后寄存器里的值往往是溢出值或无效值比如16#FFFF、16#8000。ST里做数据判断时一定要先判断数据有效性再做工程量转换和报警逻辑。我在FB_TempProcess里加了bSensorFault判断就是专门处理这种状态原始值小于0或大于27648直接判定传感器断线或通信故障而不是让程序继续用垃圾值去算温度、触发错误报警。4.5 在线修改和下载的坑NX支持在线修改功能但ST功能块改了代码后在线变更时如果功能块引脚数量变了很多情况下系统会提示“无法在线变更需要停止后下载”。这时候千万不要强行下载否则正在运行的设备会停机。我的习惯是改常量参数在线写值改完导出备份。改功能块内部逻辑但引脚不变直接在线变更系统会短暂停一下该任务但其他任务可能继续跑。改引脚结构、换功能块实例停下PLC完整下载再冷启动。为了减少这种停机次数我会在ST功能块里尽量多留一些可调的输入参数把滤波系数、量程上下限、报警阈值全部做成引脚而不是写死在代码里。这样现场调参根本不碰程序也就不会触发在线变更的限制。5. 写在最后的一点个人体会把ST和梯形图混着用这件事本身没有标准答案。我见过有团队把整个程序全用ST写也见过有人坚持全梯形图两种方式都能跑。但对我来说“数据处理用ST逻辑用梯形图”这个分工让现场维护、团队协作和程序复用都轻松了不少。特别是NX系列这种本身定位在高端运动控制和数据交互的平台如果还抱着老一套全梯形图思路等于把机器人的腿绑成一条去跑步。现在接项目我拿到需求后第一件事就是画一张分工表哪些信号要滤波运算哪些数据要打包上传哪些阀要按顺序动作哪些报警要互锁锁存。然后再去决定每个POU用什么语言。ST不是要把梯形图赶尽杀绝梯形图也不是老古董。它们俩配合得好一个管“计算”一个管“动作”整个程序才真正像一个现代PLC该有的样子。下次再有人问欧姆龙NX系列PLC用ST还是梯形图我一般就回一句看这个变量是算出来的还是干出来的就知道该往哪儿放了。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询