前阵子在现场调一台三轴贴标设备用西门子S7-1200搭配步进和伺服混用电气图纸看着简单程序倒是把我折腾得不轻。当时最头疼的问题就是每个轴的运动控制逻辑写起来大同小异但报警处理、回零、限位、使能这些细节各有各的坑光复制粘贴就弄了几百行重复代码改一个轴的参数要翻半天。后来痛定思痛把整套运动控制封装成了一个FB块项目收尾时回头算账光是调试时间至少省掉了三分之一。所以今天想聊的就是关于S7-1200平台下伺服和步进电机控制的FB块程序设计。标题叫高效控制的得力助手一点不夸张——只要你手上有不止一个轴要控制哪怕只有两个封装一个自己的FB块都是值得的。这篇文章不催眠不堆术语就讲清楚我怎么做、为什么这么做、踩过哪些坑希望对正在搞1200运动控制的同行有点帮助。如果你刚接触1200的运动控制或者已经在用Motion Control指令但觉得项目里代码太乱、轴一多就失控这篇文章正合适。1. 为什么非要自己写一套FB块来控制伺服和步进1.1 直接调库函数的痛谁用谁知道S7-1200从固件4.0开始运动控制功能就集成了PLCopen标准的那一套指令比如MC_Power、MC_MoveAbsolute、MC_MoveRelative、MC_Home这些。理论上说你只需要在程序里拖几个指令块配上工艺对象轴就能转起来。听起来挺美好但实际项目里一用就发现问题了。假设你有三个轴——一个步进控制送料一个伺服控制贴标头升降一个伺服控制旋转。每个轴都需要使能、回零、点动、绝对定位、相对定位、暂停、复位、报警复位。如果你直接在每个程序段里堆MC指令会发生什么每个轴的MC_Power、MC_MoveAbs都占一片程序区输入输出参数一大堆背景数据块满天飞。最要命的是你的调用方式还不统一——A轴用LAD写的B轴用SCL写的等设备交付后别人来维护看到3000行程序里有十几套运动控制逻辑心态直接爆炸。所以第一个问题不是要不要封装而是什么时候开始封装。我的答案是只要项目里有两个以上的运动轴或者你预计以后的项目还会用到类似控制就应该封装。一次投入反复受益。1.2 裸调指令和封装FB的差别就像用车床和用手锉裸调指令的定位是完成一个动作而封装FB的定位是面向工艺的操作。打个比方裸调指令就像给了你一把锉刀和一块铁你想做一个螺丝每次都得自己量尺寸、手动锉质量还不稳定。封装FB则像一个简易车床你设定直径、长度、进给量一按开关它就车出来一根标准件。在实际项目里HMI上的操作员不会关心你调用了哪个MC指令他只需要按启动停止回零按钮。触摸屏脚本如果直接面对MC_Power和MC_MoveAbs你要在画面里处理一堆使能状态、忙状态、错误状态脚本写起来又臭又长。但是如果有一个FB块接口就是启动信号、目标位置、速度内部把一切脏活累活都干完HMI的脚本就简单到令人感动。更重要的是错误处理。直接调库函数时如果某个轴报错你需要逐个查它的错误位、报警代码然后手动复位。而FB块内部可以统一处理错误来了先停所有运动输出错误代码等操作员确认后复位全程只有一个错误复位输入和一个错误代码输出。这就是封装带来的核心价值把复杂留给自己把简单留给别人。1.3 多轴项目里FB块的复用性才是王道S7-1200的FB和SFB最大的优势是可以多次调用。你写一个FB100作为轴控逻辑然后Main OB1里调用FB100的三个实例分别对应轴A、轴B、轴C。每个实例都有自己的背景数据块互不干扰。这意味着什么呢意味着你只需要维护一套代码三个轴的行为逻辑完全一致永远不会出现A轴改了逻辑忘了改B轴的情况。此外如果项目后期要增加第四个轴只需要在组态里加一个工艺对象然后把FB100再拖出一个实例配上参数就行了。整个过程可能连十分钟都不到。这种扩展性对于工期紧张的工程项目来说是实实在在的救命稻草。我后来还做过一个项目四个伺服轴共用同一个FB块参数全部放在背景数据块里现场调试时只需要调整每个轴的HMI配方参数程序一行没改。2. 运动控制底座S7-1200控制伺服和步进的核心机制2.1 从脉冲到报文两种截然不同的控制路径S7-1200控制步进电机最常见的方式是PTO脉冲输出。1200本体上集成了若干个高速输出点具体看型号常见的有100kHz和200kHz两种通过组态PTO/PWM技术可以输出脉冲信号和方向信号给步进驱动器。这种方式优点是简单、成本低、抗干扰尚可缺点是精度受限于脉冲频率而且没有位置反馈除非你另接编码器属于开环控制。而控制伺服电机主流方案是用PROFINET通信。1200通过PROFINET接口与伺服驱动器通信使用标准报文比如报文2、报文3、报文111进行周期性数据交换。PLC发送控制字、目标速度、目标位置驱动器返回状态字、实际位置、实际速度。这种方式是闭环控制精度高、能反馈真实位置、能实时读取驱动器报警成本也高。当然也有用1200发脉冲控制伺服驱动器的省钱方案但那样就浪费了伺服的闭环优势我一般不建议。所以当你设计FB块时首先要明确一个问题这个轴是脉冲轴还是通信轴这决定了FB块内部的指令调用方式。一种做法是写两个FB块分别对应两种方式另一种做法是在一个FB块里设置模式参数内部根据模式切换调用逻辑。我推荐后者因为90%的业务逻辑是一样的只有最底层的指令调用不同。2.2 工艺对象让PLC认识你的轴不管是脉冲轴还是通信轴在TIA Portal里都需要为每个轴创建一个工艺对象。工艺对象就是PLC内部的轴档案里面记录了轴的名称、单位、每转脉冲数、螺距、最大速度、加减速时间、软限位、硬限位方向、回零模式等等一堆参数。一个常见误区是工艺对象里的参数随便填反正PLC能转。等到调试时就傻眼了——电机转一圈走多少毫米不对、速度显示离谱、软限位乱触发。工艺对象里的每转脉冲数和每转位移量是运动控制计算的基础。比如丝杠导程是5mm步进电机转一圈要1600个脉冲200步×8细分那每转脉冲数就填1600每转位移量就填5.0单位是mm。如果填错了位置换算全乱套设备动作肯定不对。此外1200的运动控制指令是基于工艺对象的。你调用MC_Power时指定轴名称调用MC_MoveAbsolute时也是指定轴名称。这意味着工艺对象是在组态层面就绑定的FB块内部只需通过轴名称找到对应工艺对象即可。2.3 标准报文的坑PROFINET伺服最容易出问题的地方如果用的是PROFINET伺服报文类型的选择直接影响你PLC侧能读到什么数据。报文2是基本速度控制PLC发速度设定值收实际速度不涉及位置控制报文3是在报文2基础上增加了位置控制字和目标位置报文111则是带位置实际值的标准报文常用于定位应用。很多人包括我第一次配置伺服通信时都踩过这个坑把报文类型选错了或者PLC侧和驱动器侧的报文不一致。结果就是控制字发不过去、状态字读不回来轴完全不受控。排查方法很简单在TIA Portal的网络视图里查看PLC与驱动器之间的通讯报文是否匹配IO地址有没有分配满。干这行久了你会发现PROFINET伺服调试中百分之六十的问题都出在报文配置上而不是程序本身。3. 轴控FB块的整体设计接口、状态机与控制逻辑3.1 外部接口设计少而精的管脚一个好的FB块接口不是越多越好而是越贴合工艺越好。我设计的这个轴控FB块接口分几个方向。输入接口方面有使能信号、回零触发、回零模式、绝对定位触发、目标位置、目标速度、加减速时间、相对定位触发、偏移量、点动方向、点动速度、暂停触发、急停复位、错误复位。输出接口方面有当前状态空闲/运行/回零/暂停/故障、当前位置、当前速度、实际速度、回零完成、定位完成、错误代码、忙信号。这些接口参数归在一起看基本上覆盖了现场操作员需要的一切。在触摸屏上每一个按钮对应一个触发信号每一个显示控件读取一个输出值清晰明了。有的人喜欢把回零、绝对定位、相对定位、点动都拆成独立接口我建议不要这样——接口太多HMI脚本维护就是灾难。把触发源统一定义成一个枚举值或者几个独立的BOOL根据工艺需求取舍即可。这里有个设计心得不要把FB块做成万能块——试图兼容所有可能的情况。接口每多一个调试成本就会增加很多。宁可做两个简化版FB也不要做一个复杂到没人敢用的大而全。我最初设计的FB块有40多个管脚后来砍到25个左右用起来才顺手。3.2 状态机FB块的核心骨架FB块内部必须有清晰的状态管理。我采用的是标准的状态机方式空闲、使能中、回零、就绪、运行、暂停、完成、故障。从空闲开始收到使能信号后进入使能中同时调用MC_Power等待Power指令返回已使能状态后进入就绪。在就绪状态可以接收各种运动指令——绝对定位、相对定位、点动。每次运动完成后回到就绪但有一个完成状态的脉冲输出告诉HMI这次动作结束了。故障状态是另一个重要分支。无论是MC_Power报错还是MC_MoveAbs报错还是驱动器报警都要进入故障状态。在故障状态下所有运动指令都被封锁只能执行错误复位。错误复位信号到达后先调用MC_Reset指令然后回到空闲状态重新使能。这个设计确保了设备在故障后不会被半吊子地重新启动。状态机的好处是逻辑清晰、排错容易。现场调试时操作员如果看到FB的状态卡在运行出不来你就知道是运动指令没有返回完成信号顺着这个方向查就能定位问题。如果没有状态机所有的运动逻辑搅在一起定位问题会非常痛苦。3.3 内部控制的细节MC指令的配合与信号衔接FB块内部调用西门子运动控制指令时有几个细节必须处理好。第一个是MC_Power的Start信号。MC_Power的Start是上升沿触发你不能一直给true。我习惯用使能信号的上升沿来触发MC_Power.Start然后通过Status输出判断是否已完成使能。另一个要注意的是MC_Power的StopMode参数——如果设为0是紧急停止立即停止不按减速停止设为1是带减速的停止。我建议设为1除非你确实需要瞬间停止。第二个是定位指令的启动信号处理。MC_MoveAbsolute.Done信号是运动完成时的一个脉冲你需要把它锁存起来否则HMI可能捕捉不到。我的做法是当Done出现时置位一个内部标志完成输出然后等待HMI发送复位完成标志输入后才清除。这样HMI端看到的完成信号是一个稳定的置位状态不会一闪而过。第三个是超时监视。在实际项目中机械卡住、伺服报警等情况会导致运动指令一直不返回完成信号。我习惯在每个运动指令启动的同时启动一个定时器比如设定30秒。如果30秒后Done还没出现直接判定故障停止运动并报警。这个设计救过我很多次——没有超时监视的FB一旦机械卡住PLC就会一直等整个设备陷入僵尸状态。4. 手把手搭建一个可复用的轴控FB从组态到调试4.1 第一步TIA Portal里的轴组态和关键参数计算打开TIA Portal在PLC工艺对象下添加新对象选择轴类型。组态中选择轴的驱动方式——脉冲还是PROFINET然后按向导设置参数。脉冲轴的参数重点是高速输出点选择。以S7-1200某型号为例高速输出点通常是Q0.0、Q0.1这类集成输出PTO模式可以支持较高的脉冲频率。如果你的应用要求200kHz以上可能得考虑选用带更高频率的型号或者外置高速输出模块。计算每转脉冲数时别只看电机的细分——要包含驱动器上的拨码开关设置。比如步进电机本身是200步/转驱动器细分数设为8那每转脉冲数就是200×81600。再配合丝杠导程每转位移量填5.0mm这样PLC内部就能把脉冲数换算成毫米位置。PROFINET轴组态时要先在设备和网络中把伺服驱动器挂到IO控制器的PROFINET系统下设定设备名和IP地址。设备名必须和驱动器侧一致否则通信建立不了。然后分配IO地址按照选择的报文类型对应控制字和状态字的位置。我在组态完成之后通常会在PLC变量表里把控制字、状态字、目标位置、实际位置这几组变量的地址记下来后面调试时监视起来方便。4.2 第二步编写FB块的SCL核心代码这个FB块我用SCL写而不是LAD。原因很简单SCL适合描述状态机和复杂逻辑代码紧凑而且可以CtrlC/V快速创建多轴实例。你可以用LAD写但当状态分支超过五个时LAD的梯形图区域会非常大看起来费劲。核心结构是一个CASE语句。大致逻辑如下CASE #State OF 0: // 空闲 IF #Enable AND #EnableEdge THEN #Power.Start : TRUE; #State : 10; END_IF; 10: // 等待使能 IF #Power.Status TRUE THEN #State : 20; END_IF; IF #Power.Error THEN #ErrorCode : #Power.ErrorID; #State : 900; END_IF; 20: // 就绪等待运动指令 IF #HomeCMD THEN #Home.Start : TRUE; #State : 30; ELSIF #AbsPosCMD THEN #MoveAbs.Position : #TargetPosition; #MoveAbs.Velocity : #TargetVelocity; #MoveAbs.Start : TRUE; #State : 40; END_IF; ... 900: // 故障状态 IF #ErrorReset THEN #MCReset.Execute : TRUE; #State : 0; END_IF; END_CASE;这段代码只是示意实际项目中每个状态还要处理Done、Busy、Error、CommandAborted这些指令输出。指令的实例名比如#Power、#MoveAbs、#Home这些需要在FB块内部声明为程序调用时的内部背景也就是在OB1中分别实例化对应工艺对象。有一点很重要MC指令的轴参数必须在FB内部正确绑定到对应的工艺对象。比如MC_MoveAbsolute中的Axis参数要选择你组态的轴1还是轴2。多轴调用时每个FB实例内部的MC指令实例都是独立的所以各轴的轴名称绑定不能搞混。建议在给FB创建实例时把背景数据块的名称起得和轴一一对应比如FB_Axis_Instance_A对应轴A这样不容易出错。4.3 第三步空载调试、加负载调试和Trace的使用程序写完不要急着连电机就跑。先把工艺对象组态中的最大速度和最大加速度设得很保守——比如只有工艺设计转速的百分之二十。这样即使位置指令给错了机械也不会撞坏。我在现场的第一版参数通常都极保守确认一切正常后再逐步提高。然后先不带负载跑回零。把目标位置给一个固定值触发绝对定位观察位置实际值是否按照预期方向变化。注意方向—— 很多驱动器支持方向信号反接如果脉冲方向和实际机械方向不一致只要在驱动器参数或者工艺对象勾选方向取反就能解决。这个坑很常见而且很容易让人误以为程序写错了。带负载之后重点看加减速特性。如果加速度太大机械结构会有明显冲击甚至导致伺服过载报警。此时要放慢加速度而不是一味怀疑参数不对。另一个重要工具是TIA Portal的Trace功能也就是轨迹记录。用Trace可以记录轴的实际位置、设定位置、实际速度、控制字等变量直观地看到跟随效果如何、位置曲线有没有超调。我调试运动控制时基本离不开Trace——特别是排查定位不准、过冲、抖动这类问题时看曲线比看数据感觉直观得多。5. 现场故障实录运动控制FB最常见的坑与排查套路5.1 报警类故障速查使能、限位、驱动器报警先说使能不上的情况。当你给了Enable信号MC_Power却一直不返回Status最常见原因是伺服驱动器的硬使能端子没有接通。很多伺服驱动器除了通信控制还需要额外的硬使能接线或者拔插端子设置。如果驱动器的使能物理端没导通PLC这边发多少使能指令都没用。排查方法是直接看驱动器的面板或软件状态确认驱动器是否处于伺服使能状态。限位报警是另一个高频问题。工艺对象里配置了硬限位——外部接的限位开关还有软限位——设置的软件位置范围。实际项目中限位开关的信号极性是常闭还是常开很容易接错搞混。排查时先看PLC输入点是否读到预期的0/1信号然后再看工艺对象的限位状态位。我在现场处理过一个案子设备一启动就报正限位结果发现是限位开关的公共线接错两个限位信号一直是同一个状态怎么调都报警。还有一个1200特有的坑叫轴未启用。当你调用了MC_Power之外的运动指令但轴没有先使能或者工艺对象里的使能逻辑没满足PLC会报轴未启用之类的错误。我的办法是把所有运动指令都加上前置条件如果轴不在使能状态不发送启动命令。这也是FB状态机的价值所在——状态的跳转顺序本身就是一层保护。5.2 定位不准类故障脉冲丢步、电子齿轮比、回背隙定位不准是个大类表现五花八门——位置差一点、越走越偏、偶尔停错位置。如果是脉冲轴优先怀疑丢步。丢步通常是因为脉冲频率太高、加减速太陡、或者电机带不动负载。排查时听声音——电机如果咔咔响多半是丢步了。解决思路是降低速度或者延长加减速。另一个原因是驱动器的电流设置不够电机扭矩不足稍微有点负载就丢步。把驱动器电流调到额定范围内再试试手感——用手轻微抵住负载看看电机是否还走得动。电子齿轮比设置错误也会导致定位不准。伺服驱动器里的电子齿轮比决定了PLC发一个指令单位对应电机实际转多少圈。如果这个比值算错了电机走的距离就不对。公式并不复杂但每个驱动器品牌定义不同有的是分数形式分子/分母有的是乘数形式搞混了就会偏差一个固定比例。我习惯在组态完成之后让轴走一个已知长度比如100mm量一下实际移动距离一比就知道齿轮比对不对这比对着手册反复验证快得多。机械回背隙则是物理层面的问题丝杠反向间隙大、连轴器松了都会导致反向定位不准。处理办法是尽量单向定位或者通过参数做反向间隙补偿。但补偿值要根据实际测量来不要拍脑袋填。我第一次做时拍脑袋填了0.5mm结果反向过冲位置越走越歪还以为是电子齿轮比的问题查了半天。5.3 通信与组态类故障PROFINET的三大常见病PROFINET伺服通信故障十有八九出在设备名、IP地址、报文配置这三件事上。设备名不一致最常见——你在TIA Portal里给驱动器分配的设备名必须和驱动器自身保存的设备名完全一致这台设备才会上线。注意设备名下划线、大小写都要一致少一个字符就离线。IP地址则是另外一个独立检查项。PROFINET IO通信本身不依赖IP但很多调试软件和诊断工具是需要IP的而且IP设置不对还会导致设备诊断不到。我在现场见过IP和IO设备不匹配导致整个PROFINET网络通讯断断续续的案例后来把IP段统一规划问题立刻消失。报文配置的错误表现形式更多样。有的能连上但轴不动是因为控制字发的位置不对有的实际位置读出来一塌糊涂是因为报文类型里根本没有位置反馈。排查思路是把PROFINET通信建立好之后先用在线监视看IO数据——控制字有没有正确写入状态字读回来的数值是不是符合预期。如果控制字已经写了但驱动器没反应基本都是报文映射或者驱动器的参数配置问题不要怀疑PLC程序。5.4 调试心得一套可以复用的排查顺序我自己调试运动控制FB时有一个固定的排查顺序。首先确认通信建立就是PROFINET设备在线或者脉冲轴的高速输出点没有损坏第二步看使能状态确认轴已经处于受控状态第三步看指令执行确认MC指令有没有启动、有没有报错第四步看实际运动确认方向、速度、加减速是否合理最后看定位精度确认位置是否准确。这套顺序像体检一样每一步都排查完90%的问题都能定位。千万不要一上来就怀疑FB块逻辑写错了——大多数情况下FB块如果在自己电脑上仿真过逻辑本身是不会有问题的反而外围接线、参数配置这些看起来低级的地方才是故障高发区。6. 写在最后封装FB块的真实体会与延伸建议回头看看封装这个轴控FB块确实是我在1200平台上做的性价比最高的决策之一。它不仅让当前项目调试轻松了很多更重要的是在后续项目中我可以直接复用这套思路和大部分代码。只要工艺对象参数重新填好FB块的接口和逻辑都不用动新项目就能快速投入运行。我甚至可以在多个工程师之间分享这个FB规定好接口定义大家各自写轴的应用部分互不干扰项目进度快很多。有几个经验算是踩坑总结出来的第一FB块内部尽量使用SCL而非LAD状态机写起来清晰得多后期维护也友好。第二FB块的接口宁缺毋滥不要试图把所有功能都塞进去复杂度和易用性永远是对立面。第三背景数据块的参数注释一定要写全——HMI脚本工程师可能不知道那个备用速度是什么但有了注释他一猜就明白是手动速度上限。第四使能和急停逻辑一定不能省。我曾经为了省事把MC_Power的StopMode设为紧急停止结果现场急停一按机械轴哐当一声直接砸下去从那以后我再也不敢省这个参数了。最后再分享一个小技巧如果你的项目中既有伺服轴又有步进轴完全可以共用这一个FB块。只要在FB内部加一个轴类型的枚举参数根据类型决定走PROFINET还是PTO的逻辑分支即可。这样多个轴的交互逻辑联锁、顺序启动可以写在一个公共程序段里调试和排查都方便不少。你手头如果有类似的1200运动控制需求不妨从这次就开始封装吧——写一次用三年值。