ST语言与梯形图混合编程:欧姆龙CP1H自动组装线PLC实战
前段时间交付了一条小型自动组装生产线控制系统用的欧姆龙CP1H PLC。这套程序的特别之处在于气缸动作、输送带启停、三色灯这些逻辑控制全部走梯形图而配方选择、产量统计、串口扫码解析、进制转换这类跟数据打交道的活儿全部用ST语言处理。两者在同一个工程里共存各干各的活互不干扰。做完这个项目之后我最大的体会是——ST语言和梯形图不是替代关系而是互补关系。你要是能把这两套东西配合好写出来的程序既好读又好看而且逻辑维护起来轻松得多。这篇内容不打算讲枯燥的理论就围绕这条自动组装线把程序架构、IO规划、典型代码段、调试中踩过的坑都摊开来说。做设备维护的、写PLC程序的、甚至刚入行想了解ST语言怎么用的朋友应该都能从这里找到点有用的东西。1. 项目背景与控制需求拆解1.1 这条自动组装线要实现什么先交代一下项目背景。客户要组装一个小型的机电产品工艺路线不算复杂但节奏要求比较高上料、定位夹紧、压装、检测、分拣输出五个工位目标节拍是单件12秒以内。线体上配了两台气缸、一台夹紧气缸还有一台步进电机负责工位间的传送定位另外有一个扫码枪需要读取工件上的条码信息把数据存入PLC用于追溯。工艺顺序大致是这样人工把工件放到上料位光电传感器检测到有料后定位气缸伸出把工件卡住接着压装气缸下压完成装配压装到位后升起然后步进电机把托盘推到检测工位检测传感器判断装配结果合格的送到下料位不合格的推到NG料箱。这个流程听起来简单但真正写程序的时候你会发现里面藏着不少细节气缸的动作必须严格按顺序来不能同时伸出缩回扫码枪的数据是ASCII字符串需要解析成能用的条码编号检测结果要跟当前工件的条码绑定方便客户做质量追溯产量、合格率这些数据要实时统计并显示在触摸屏上。这些都是程序层面的设计问题不是简单把IO接上就能解决的。1.2 从控制需求反推程序结构我的习惯是先列控制需求清单再决定用什么程序结构来实现。这条线整理下来大概是这几类顺序控制五个工位的气缸、传送、分拣必须按步骤执行步与步之间有明显转移条件手动调试每个气缸、电机都要能单独动作方便装配调试和故障处理数据处理条码解析、产量统计、合格率计算、配方参数管理报警管理气缸超时、气压不足、急停复位、伺服报警要能区分优先级并在触摸屏上显示安全处理急停必须在硬件回路里切断负载而不是只靠程序逻辑清单列完后程序结构已经比较清晰气缸和电机这类设备控制用梯形图因为梯形图在表示顺序步进、互锁逻辑的时候非常直观数据采集和运算用ST语言因为它处理字符串、数组、数学运算的时候比梯形图高效太多。这也是最终选择ST梯形图混搭方案的根本原因。2. 编程方案选型为什么ST语言要和梯形图混搭2.1 梯形图到底强在哪弱在哪梯形图出现到现在几十年了至今仍然是PLC编程的主流语言原因就四个字直观、好查。一个维护电工拿着图纸看梯形图能顺着左母线一路看到右母线哪个触点接通了、哪个线圈没输出眼睛一扫就知道问题出在哪。这在产线维护场景里是巨大的优势。但梯形图有个明显的软肋遇到复杂运算的时候就力不从心了。你说要把一个ASCII字符串里的十六进制字符转成十进制数再用到手写一堆比较指令、移位指令、转换指令梯形图能把你画到怀疑人生。不信你可以试试用梯形图计算一个产品的合格率百分比还得带一位小数——梯形图做浮点运算的指令本身就少程序行数却会翻好几倍。这种场景梯形图的效率就很低了。2.2 ST语言擅长做什么不擅长做什么ST语言其实就是结构化文本语法跟Pascal比较接近。它的强项恰恰是梯形图的弱项字符串处理、数组运算、数学计算、CASE分支选择、FOR循环——这些在ST里面写起来非常舒服程序条理也很清晰。但ST语言也有短板最大的问题是看不到逻辑流。一段完全用ST写的程序如果变量命名不规范、注释不到位别人接手的时候会很痛苦。尤其是现场维护电工很多不会ST语言你让他们去读一段几十行的ST代码不如直接给他们看一张梯形图。所以ST写在程序里要克制、要配合好注释不能滥用。2.3 混合编程的分工边界我对混合编程的建议是按照数据的流动来划分边界。设备动作、互锁、急停、手动自动切换这些跟硬件接线强相关的逻辑放梯形图里。凡是现场维护时需要一眼看懂的都应该画成梯形图。凡是涉及数值计算、协议解析、配方管理、统计报表的逻辑放ST里。这些逻辑天然适合用文本形式表达而且平时不怎么需要现场维护的人去翻。用欧姆龙编程软件CX-Programmer或Sysmac Studio建工程的时候同一个PLC程序里可以同时存在多个梯形图程序段和ST程序段他们之间通过全局变量互相访问。这种安排非常灵活等于你既享受了梯形图的高可读性又获得了ST的高计算效率不带任何妥协。3. 硬件选型与IO地址规划3.1 PLC选型为什么选CP1H这条自动组装线没有太多模拟量输入也没有高速计数需求但需要驱动步进电机做定位。欧姆龙这个定位需求很典型CP1H自带四路100kHz的脉冲输出无论是驱动步进驱动器还是伺服驱动器都够用。相比起另外加定位模块的方案用内置脉冲口能省掉一个模块的成本和接线工作量。CP1H还内置了RS232C串口正好可以接扫码枪做数据读取不需要额外扩展通信板。再加上CPU本体自带以太网口触摸屏和上位机连接都方便。综合下来CP1H-XA40DR-A继电器输出带模拟量输入在这个项目里性价比最高。当然如果你要控制的轴数更多或者要求整体以太网同步运动控制那可以直接上NJ/NX系列那边Sysmac Studio的体验会更现代化。但就这条线来说CP1H足够了。3.2 IO地址分配表输入与输出的区别搞PLC的人经常问梯形图输入与输出的区别——这句话问的就是IO映射的本质。输入区是现场传感器信号进入PLC的大门比如光电传感器、磁性开关、按钮它们把外部通断状态读进CIO区输出区是PLC控制外部负载的大门比如电磁阀、接触器、指示灯程序往CIO区写状态模块再把它转成实际的通断。你要记住一条基本规则输入点只能被程序读取程序只能往输出点写反过来不行。这条线的地址分配我列成了一张表地址功能说明信号类型0.00急停按钮常闭输入0.01启动按钮常开输入0.02停止按钮常闭输入0.03手动/自动切换输入0.04复位按钮输入1.00上料光电传感器输入1.01定位气缸伸出到位输入1.02定位气缸缩回到位输入1.03压装气缸下到位输入1.04压装气缸上到位输入1.05检测工位结果OK输入1.06检测工位结果NG输入100.00定位气缸伸出电磁阀输出100.01定位气缸缩回电磁阀输出100.02压装气缸下行电磁阀输出100.03压装气缸上行电磁阀输出100.04夹紧气缸夹紧电磁阀输出100.05输送带电机接触器输出100.06三色灯绿色输出100.07三色灯红色输出100.08三色灯黄色输出100.09蜂鸣器输出IO地址规划有一条实用经验输入输出分区要留余量不要把地址排得太满。比如输入从0.00开始排排到1.06就停后面留几个空位给现场加信号用。CP1H的输入输出地址是跟着模块走的所以排地址之前一定要确认模块安装在哪个槽位不然就会错位。4. 程序架构与核心代码实现4.1 程序总架构与任务划分CP1H的程序默认有多个任务比如周期性任务和中断任务。我的习惯是主流程放在周期执行任务里把扫描周期设成10ms以上这类的固定周期保证气缸动作时间控制得比较准确。如果涉及高速计数、脉冲输出需要用到中断任务不过这条线不需要所以没有额外配置。工程内部我分成几大段主控程序段跑自动流程的梯图步进逻辑手动程序段让操作员在调试模式单独动作气缸和电机ST程序段处理扫码数据、配方、产量统计报警程序段负责超时判断、三色灯驱动。欧姆龙支持在一个工程里同时建多个程序段每个程序段可以是梯图或ST这种架构用起来非常顺手。这里有个细节要注意CP1H的任务执行顺序影响程序逻辑。如果多个程序段同时访问同一个变量你要保证写操作不会互相覆盖。我的做法是规定谁写变量谁能读变量——比如产量统计只允许ST程序段写梯形图只读不写气缸动作标志只允许梯形图写ST程序段不碰它。这样程序之间就不会打架。4.2 梯形图实现气缸顺序控制自动流程我用的是典型的步进式梯形图俗称步进楼梯。每一行就是一个步骤步骤转移条件就是这个步骤的楼梯台阶。举个例子定位气缸的伸出逻辑第一步是等待上料光电感应到工件然后定位气缸伸出。梯形图的写法就是当前步骤标志、光电传感器常开触点、气缸伸出到位信号作为下一步的转移条件。气缸伸出到位之后下一步动作才允许压装气缸下行。这样一步一步排下来逻辑非常清楚现场人员排查故障的时候只要看当前是哪一步亮着就知道设备卡在哪了。气缸动作还有一个必须做的互锁同一个气缸的伸出和缩回电磁阀绝对不能同时输出。梯形图里要串对方的常闭触点做硬件互锁程序里也要做双线圈检查。所谓的双线圈就是同一个输出位在程序里写了两次或两次以上比如100.02这个位既在自动流程里写了又在手动流程里写了扫描到最后一次写的结果才生效这样很容易出问题。用欧姆龙编程软件自带的交叉引用表查一下就避坑了。4.3 ST语言实现配方、统计与数据处理这才是ST语言大显身手的地方。先说配方选择。客户端产品有3种规格每种规格对应的压装力度、节拍时间、检测阈值都不一样。这种分支逻辑用梯形图写就像一团乱麻但ST写起来非常流畅我用了一个功能块输入一个配方编号输出对应的参数// 配方选择功能块 FB_RecipeSelect // IN: i_RecipeNo 配方编号(1~3) // OUT: o_CycleTime 节拍时间, o_PressForce 压装力度, o_AllowNG 是否允许NG品流到下道 CASE i_RecipeNo OF 1: o_CycleTime : 2.5; // 节拍2.5秒 o_PressForce : 1500; // 压装力度 o_AllowNG : FALSE; 2: o_CycleTime : 3.0; // 节拍3.0秒 o_PressForce : 2200; // 压装力度 o_AllowNG : TRUE; 3: o_CycleTime : 2.0; // 节拍2.0秒 o_PressForce : 1800; // 压装力度 o_AllowNG : FALSE; ELSE: o_CycleTime : 0.0; o_PressForce : 0; o_AllowNG : FALSE; END_CASE;CASE语句放在梯形图里是想都不敢想的但在ST里面几行就搞定可读性也强。再说产量统计。生产报表要求统计总产量、合格数、不合格数、合格率客户那边触摸屏要实时显示。用ST写这个逻辑就非常轻松// 产量统计功能块 FB_ProductionCount // IN: i_RunSignal 运行信号, i_DetectOK 合格信号 // OUT: o_TotalCount 总产量, o_OKCount 合格数, o_NGCount 不合格数, o_Rate 合格率% IF R_TRIG_Start.CLK : i_RunSignal AND R_TRIG_Start.P THEN o_TotalCount : o_TotalCount 1; END_IF; IF i_DetectOK THEN o_OKCount : o_OKCount 1; ELSE o_NGCount : o_OKCount 1; // 这一行应该是NG见下面代码 END_IF; o_Rate : INT_TO_REAL(o_OKCount) / INT_TO_REAL(o_TotalCount) * 100.0;等一下上面我写错了一行NG统计应该单独计数。实际代码是这样IF _NOT_ i_DetectOK THEN o_NGCount : o_NGCount 1; END_IF;由于检测工位每一件都判定OK或NG合格加不合格就等于总产量所以也可以直接用减法NG 总数 - 合格。这个看个人习惯但要注意别重复统计。还有一个功能是条码解析。扫码枪通过RS232给PLC发一串ASCII字符比如一行ABC123*ST里读取串口接收缓冲区然后用字符串处理指令截取有效部分再转成能显示的字符串。这里ST的字符串处理函数就非常高效了。网上有人问S71200中将10进制转换为16进制的程序梯形图说实话用梯形图写进制转换确实痛苦用ST写也就一行函数的事。欧姆龙的ST里同样支持各种转换函数调试的时候一条指令搞定非常省事。最后是数据计算比如合格率百分比换算成触摸屏能显示的整数。ST里直接写就行// 把0~100的实数值放大到0~1000方便触摸屏显示整数百分比 o_DisplayRate : INT_TO_REAL(TRUNC(o_Rate * 10.0));4.4 功能块封装把ST和梯形图粘在一起看到这里你会发现我把配方、计数这些逻辑做成了功能块FB。欧姆龙支持在梯形图里面拖一个功能块调用然后填写输入输出参数。这样一来梯形图的程序段保持简洁ST语言的逻辑都封装在功能块内部。这个设计非常关键因为它就是ST和梯形图结合的桥梁。打个比方梯形图就像一个设备的面板上面有按钮和指示灯ST功能块就是藏在面板背后的控制电路。操作员只看面板就能操作和维护而复杂的计算逻辑被藏起来了。功能块还能重复使用第二条产线直接复制这个FB改改参数开发效率和一致性都提高了。功能块封装要注意变量的作用域。内部变量定义成局部变量外部接口才定义成输入输出变量。不要让FB内部逻辑去修改全局变量否则这个功能块换个项目就废了而且排查问题的时候很难定位。5. 调试实录与常见问题排查5.1 传感器误信号与滤波处理这条线调试的时候遇到一个典型的坑上料光电传感器在气缸动作的瞬间经常会出现几十毫秒的误触发。原因很简单气缸动作引起的机械震动传导到传感器支架导致光电信号瞬间闪断。排查方法先看触摸屏上的IO状态监视确认误触发的频率和时机再用示波器或者PLC的输入点强制监视锁定误差。解决方式是两种组合第一传感器支架加橡胶减震垫第二程序里加延时滤波要求信号稳定超过20ms才认为是有效信号。用梯形图写这个滤波比较直观就是一个定时器加触点判断用ST写也一样几行代码就能实现。5.2 气缸到位信号丢失的套路化排查很多时候气缸明明到位了但程序就是不走下一步原因基本都在磁性开关或接近开关上。调试过程中最常见的问题是磁性开关安装位置太靠边气缸活塞到位了但磁环没有完全经过开关的感应范围或者是开关接线端子松动震动之后信号时有时无。我排查这类问题的套路是这样的先在IO监视表里强制接通到位信号看程序能不能往下走如果能说明程序逻辑没问题问题在信号检测环节然后去调整磁性开关位置让它刚好在气缸到位时点亮最后检查接线端子重新压紧一遍。这套排查流程我大概处理过不下二十起基本都能快速定位。还有一条经验气缸电磁阀如果用的是单线圈双位置、断电保持型不存在断电回位的问题但双线圈阀体就必须严格做互锁否则同时得电会对气缸造成冲击。这个在之前的梯形图互锁部分强调过现场再核对一次。5.3 伺服脉冲干扰与接地问题这条线用的是步进电机而不是真正意义上的伺服但问题类似。调试的时候发现一个现象电机走位偶发偏差多走或者少走几毫米。排查下来原因是脉冲输出线跟动力线捆在同一个线槽里电机启动时动力线上的干扰串进了脉冲信号。解决办法第一脉冲线换成双绞屏蔽线并且屏蔽层单端接地第二脉冲线和动力线分槽敷设不要平行走太长的距离第三PLC输出脉冲的频率不要卡在驱动器允许的极限值留出20%左右的余量。做完这三步走位偏差的问题彻底消失了。说到这顺便提一下正反转梯形图这个热门关键词。步进电机或者伺服的方向控制本质上就一个方向信号方向信号为ON正转、OFF反转。你别把它想复杂了梯形图写一个方向输出点再加一个脉冲输出触点就实现了正反转控制。真正容易出问题的是方向切换的时序——电机可能还没完全停下来方向就变了这时候需要做先停后转的判断加一个减速等待时间。5.4 程序版本管理与双线圈检查做自动化项目程序版本管理的痛很多人应该深有体会。现场改了一版程序电脑里存了一版U盘里又拷了一版最后都搞不清楚哪一版在运行。我的习惯是每次修改程序都在程序头部注释里写明日期、修改人、修改内容同时把版本号写在触摸屏的隐藏页面上开机就能看到运行版次。比如V1.02 2024-05-18 修改压装超时时间从3s到5s。这样无论是维护还是追溯都很清楚。双线圈检查是梯形图写完之后必须做的一步。在CX-Programmer里用交叉引用功能搜索每个输出线圈的地址看它出现过几次。如果同一地址出现在两个不同的梯图程序段里几乎可以肯定中间存在逻辑缺陷。这种问题最坑的地方在于设备平时运行正常但一旦某个条件变化输出就会莫名其妙地跳动因为它被最后执行的程序段覆盖了。调试中还遇到过一种情况就是PLC程序里用了保持继电器H区存放产量数据结果断电之后产量归零了。查下来发现地址写错了写到了普通CIO区断电肯定丢。CP1H的数据保持区是需要电池支持的换电池或者电池电压低的时候也要注意最好定期检查PLC电池状态不然统计数据突然清零客户那边可是要骂人的。最后再分享一个调试点的小技巧我在这套程序里专门加了一个调试模式——通过保持继电器H512.0来触发。在这个模式下程序会跳过气缸动作只允许单步执行方便在触摸屏上验证每一步逻辑是否正确。这个模式平时是关闭的但真到排查问题的时候它能帮你省下大量的时间。这个思路你可以直接借鉴到自己的项目里去成本很低但非常实用。