简介:针对三菱FX5U PLC的ST语言轴控制模板程序,面向工业自动化工程师与PLC编程人员,解决多轴运动控制中重复编写功能块的问题。压缩包内含原点复归、点动、定位运动三类核心FB块,采用结构化文本清晰封装,多轴场景下只需重复实例化即可复用。资源共8个文件,以6张图片直观展示程序结构与应用示意,配合txt源码说明和html教程文档,从原理到调用均有讲解,压缩包约990KB,便于快速下载查阅。已有1071人学习,适合需要快速搭建多轴运动控制程序的开发者。通过该模板可掌握ST语言编写轴控制FB块的完整思路,理解原点复归的安全机制、点动操控逻辑与定位运动的加减速处理,从而直接迁移到流水线、机械手等设备控制中,显著缩短开发周期并降低调试成本。
1. 一根轴写一遍、六根轴写六遍:用ST语言把FX5U轴控制包成FB块
某台设备上有六个伺服轴,每个轴都需要原点复归、点动和定位。最早用梯形图做,一个轴一段逻辑,复制粘贴六份,每个轴的限位、速度、目标位置参数互相穿插,改一个轴要同时翻六个程序块,调试时还经常找错地方。后来改成用ST语言把整套轴控制逻辑封装成FB块,程序主体变成一份状态机代码加六行实例化调用,每个轴只喂自己的参数,复杂度和改动成本一下子降下来。这个FX5U轴FB块模板就是干这件事的:用ST语言实现原点复归、点动、定位运动三个核心功能,FB块支持多轴重复实例化。适合正在做三菱FX5U多轴设备程序、想把重复定位逻辑从梯形图里解放出来的自动化程序员。
2. 技术选型与FB接口设计:编程语言选ST,接口按轴参数分层
2.1 梯形图写定位的瓶颈,以及ST语言为什么适合运动控制
三菱FX5U在GX Works3里支持梯形图、ST、FBD等编程语言。梯形图是多数电气工程师最熟的图形化语言,它强在离散逻辑的直观表达,按钮、继电器、伺服状态一眼能看懂。但一旦遇到大量数值计算、数组、循环、状态迁移的运动控制逻辑,梯形图就变得冗长。六轴设备程序复制六份之后,每一份都要手动改输出点、方向点、限位软元件,漏改一个就是设备一跑就撞限位的现场事故。
ST语言是IEC 61131-3标准的文本型编程语言,本质是类似Pascal的高级编程语言,有变量声明、IF/CASE/WHILE、数组、结构体、功能块实例化这些手段。运动控制恰好是程序里「线性流程+分支状态」最多的部分:原点复归要先找限位、再爬行、到位清坐标;点动要随时响应正反转和停止;定位要算目标位置、速度和加减速,还要等待完成信号。用CASE写一个状态机,每个状态对应一个流程阶段,比梯形图的一堆自锁互锁线圈好维护得多。
选ST还有一个现实原因:FB块封装和多轴实例化。同一个轴控制逻辑写成FB块后,程序里每个轴调用一次,每个实例独立保存内部变量,调用方只给速度、目标位置、指令号,不用关心内部怎么实现。后期加一个轴,主程序里多写一行实例化调用,不需要再复制一段梯形图。这就是FX5U项目里用编程语言的思路转变:从「画逻辑」变成「写逻辑+调接口」,程序的可维护性完全是两个档次。
2.2 FX5U定位指令基础:DRVZ、DRVI/DRVA与JOG点动
FX5U属于三菱MELSEC iQ-F系列,基本单元自带晶体管脉冲输出,直接接伺服驱动器或步进驱动器,脉冲数量决定位置,脉冲频率决定速度,这是轴控制最底层的物理通道。在GX Works3里,定位相关的指令常见有:DRVZ原点复归、DRVI相对定位、DRVA绝对定位、点动运行,以及各类限位、减速点信号。这套轴FB块模板不直接把指令写在状态机里,而是在指令之上再包一层逻辑层。
逻辑层统一做这些事:接收目标位置和速度并缓存、判断运动方向、等待完成信号、做超时保护;指令层只负责把逻辑层的请求翻译成FX5U的定位指令。这样分层的原因很实际:轴指令在不同固件版本和设备型号下细节有差异,逻辑层把它们隔离掉之后,换机型只改最薄的一层驱动代码,状态机这部分不需要动。
从使用者的角度看,只需要记住三件事:每个轴实例绑定一路脉冲输出;原点复归需要限位开关或减速点信号,接到输入软元件上;定位指令完成后底层会抬一个完成信号,FB块内部把它转成o_Done输出。模板程序把这三种运动方式收敛成统一的接口,调用方不需要关心底层指令细节。
2.3 FB块接口分层:输入输出与轴参数传递
接口设计直接决定了这个FB块好不好用,我把接口分成三层:指令输入、状态输出、内部私有变量。指令输入这一层只暴露使能、指令号、目标位置、速度和加减速时间;状态输出暴露忙碌、完成、错误和故障码;内部私有变量是状态机当前状态、边沿检测变量、超时计数器。
| 接口 | 名称 | 类型 | 说明 |
|---|---|---|---|
| 输入 | i_Enable | BOOL | 总使能,FALSE时强制回空闲状态 |
| 输入 | i_Command | INT | 0停止,1原点复归,2正转点动,3反转点动,4定位 |
| 输入 | i_TargetPos | DINT | 定位目标位置,单位脉冲 |
| 输入 | i_Speed | DINT | 运行速度,单位脉冲/秒 |
| 输入 | i_AccelTime | INT | 加速时间,单位毫秒 |
| 输入 | i_DecelTime | INT | 减速时间,单位毫秒 |
| 输出 | o_Busy | BOOL | 轴运动中为TRUE |
| 输出 | o_Done | BOOL | 本次指令正常完成 |
| 输出 | o_Error | BOOL | 故障标志 |
| 输出 | o_ErrorID | WORD | 故障代码 |
设计上把「轴号」从接口里拿掉了。多轴场景每个FB实例天然对应一个物理轴,不需要在接口里动态传轴号;如果非要在运行时动态切换轴号,实例内部的脉冲输出绑定就得跟着变,反而破坏实例独立性。主程序里建六个实例,每个实例内部通过p_前缀的底层信号绑定各自的输出点和限位输入。内部变量state、edgePrevCmd、timeOutCnt都是VAR私有变量,多实例之间不共享,这是FB块能「一份代码多轴复用」的核心前提。
3. 核心代码拆解:原点复归、点动、定位三套状态机怎么落地
3.1 FB块骨架:接口声明与状态机主循环
FB块的接口声明按IEC 61131-3标准写,三菱GX Works3的ST语法直接支持这种写法。关键点在于所有内部变量都放在VAR区,不上全局软元件表,这样才能保证多个实例化副本彼此独立。
(* 轴控制FB块接口声明 *) FUNCTION_BLOCK Fb_Axis VAR_INPUT i_Enable : BOOL := FALSE; (* 总使能 *) i_Command : INT := 0; (* 0停止/1回原点/2正转点动/3反转点动/4定位 *) i_TargetPos : DINT := 0; (* 目标位置,单位:脉冲 *) i_Speed : DINT := 100000; (* 运行速度,单位:脉冲/秒 *) i_AccelTime : INT := 100; (* 加速时间,单位:毫秒 *) i_DecelTime : INT := 100; (* 减速时间,单位:毫秒 *) END_VAR VAR_OUTPUT o_Busy : BOOL := FALSE; (* 轴运动中 *) o_Done : BOOL := FALSE; (* 本次指令完成 *) o_Error : BOOL := FALSE; (* 故障标志 *) o_ErrorID : WORD := 0; (* 故障代码 *) END_VAR VAR state : INT := 0; (* 状态机当前状态 *) edgePrevCmd : INT := 0; (* 上次指令号,用于上升沿检测 *) timeOutCnt : DINT := 0; (* 超时计数器 *) END_VAR接口声明里有几个值得注意的细节。所有输入输出都给了初始值,这点在PLC程序里容易被忽略:PLC上电或RUN切换瞬间,如果输出没有初值,触摸屏上可能闪一帧错误信号。o_Error、o_Done初始化成FALSE,state初始化成0,上电就进入空闲状态,不会乱发指令。
FB体主循环用CASE语句驱动,状态号分三段:0是空闲,10~19是原点复归,20~29是点动,30~39是定位。这样扩展新功能时,比如加一个回中位功能,直接分配状态号40~49,改动范围完全隔离。
(* 主状态机:0空闲,10回原点,20点动,30定位 *) IF i_Command <> edgePrevCmd THEN o_Done := FALSE; edgePrevCmd := i_Command; END_IF; IF NOT i_Enable THEN state := 0; o_Busy := FALSE; o_Done := FALSE; END_IF; CASE state OF 0: o_Busy := FALSE; IF i_Command = 1 THEN state := 10; ELSIF i_Command = 2 OR i_Command = 3 THEN state := 20; ELSIF i_Command = 4 THEN state := 30; END_IF; 10: (* 原点复归逻辑,见3.2 *) 20: (* 点动逻辑,见3.3 *) 30: (* 定位逻辑,见3.4 *) END_CASE;主循环里最核心的一段是前面的指令沿检测:i_Command <> edgePrevCmd才认为是新指令。很多人第一次用ST写定位程序会掉进这个坑——直接把IF i_Command = 4写在状态机里,结果定位指令每个扫描周期都被重新触发,轴走一段停一下。沿检测保证了一次指令只产生一次启动动作,后面的状态机等待完成信号后自动回空闲。
3.2 原点复归:从发送指令到清除当前位置
原点复归的状态机逻辑是把「发请求」和「等完成」拆成两个阶段。进入状态10后,先把p_HomeReq置TRUE,底层驱动器收到这个上升沿后执行DRVZ原点复归动作;随后状态机等着底层返回p_HomeDone。这个拆分很重要,避免在等待期间重复置位请求信号。
10: (* 原点复归执行 *) o_Busy := TRUE; p_HomeReq := TRUE; (* 上升沿触发底层原点复归指令 *) p_HomeMode := 0; (* 限位+爬行回原点方式 *) timeOutCnt := 0; state := 11; 11: (* 等待原点回归完成 *) timeOutCnt := timeOutCnt + 1; IF p_HomeDone THEN (* 底层指令层返回完成 *) p_HomeReq := FALSE; o_Busy := FALSE; o_Done := TRUE; o_CurrentPos := 0; (* 原点复归完成,当前位置清0 *) state := 0; ELSIF timeOutCnt > 5000 THEN (* 约25秒超时,按扫描周期换算 *) p_HomeReq := FALSE; o_Error := TRUE; o_ErrorID := 16#1001; state := 0; END_IF;超时计数器的写法需要结合扫描周期来换算。比如程序扫描周期是5ms,timeOutCnt超过5000就是25秒,原点复归25秒还没完成,基本可以判断是限位开关没到位或接线有问题。实际项目里我习惯把这个超时时间和故障码做成可配置参数,因为不同设备的原点行程长度差异很大,有的滚珠丝杠几秒就到位,有的长行程需要几十秒。
p_HomeReq、p_HomeDone这些p_前缀的信号,在模板程序里是FB块内部引用的底层软元件。p_HomeReq对应底层定位程序里DRVZ的触发条件,p_HomeDone对应回原点完成标志。做二次开发时,换一个轴型或者改限位接线,只需要在底层驱动块里重新映射这几个软元件,状态机代码完全不用动。
3.3 点动:速度连续输出与停止逻辑
点动和定位有一个本质区别:定位是「发一次命令等一个结果」,点动是「保持信号就动,撤掉信号就停」。所以点动状态里p_JogReq必须持续输出TRUE,不能只发一个上升沿就复位,否则轴会走一个脉冲就停下。
20: (* 点动运行 *) o_Busy := TRUE; p_JogReq := TRUE; (* 点动保持信号 *) IF i_Command = 2 THEN p_JogDir := 0; (* 正转点动 *) ELSIF i_Command = 3 THEN p_JogDir := 1; (* 反转点动 *) END_IF; IF i_Command <> 2 AND i_Command <> 3 THEN p_JogReq := FALSE; (* 命令撤销,停止点动 *) o_Busy := FALSE; state := 0; END_IF;这个状态的关键点在于退出条件:外部指令一旦不是2或3,立即撤销p_JogReq。实际接线时,触摸屏上的点动按钮如果直接映射到i_Command,按钮松开扫描周期就会把i_Command置0,状态机自动退出20状态,轴停住。这个逻辑也天然支持急停:急停回路断掉i_Enable,主循环顶部的使能判断会强制state回0,所有运动请求全部撤销。
需要提醒的是点动速度通常和定位速度不同,我一般会在实际项目里给点动单独配一个速度参数,比如点动速度20000脉冲/秒,定位速度100000脉冲/秒。这个模板里可以复用i_Speed,也可以在接口里加一个i_JogSpeed,属于看现场习惯的差异。
3.4 定位运动:目标位置、速度与完成判断
定位运动是三个功能里参数最多、最容易出问题的分支。模板程序把它分成两个状态:状态30负责缓存参数并发请求,状态31负责等待完成。在发请求之前,先做一次软限位检查,目标位置超出限位范围就直接报错,不让指令到达底层。
30: (* 定位执行 *) IF i_TargetPos > 100000000 OR i_TargetPos < -100000000 THEN (* 软限位检查,实际项目改成结构体数组里的限位值 *) o_Error := TRUE; o_ErrorID := 16#1102; state := 0; ELSE o_Busy := TRUE; p_PosCmd := i_TargetPos; (* 缓存目标位置 *) p_VelCmd := i_Speed; (* 缓存运行速度 *) p_AccCmd := i_AccelTime; (* 缓存加速时间 *) p_DecCmd := i_DecelTime; (* 缓存减速时间 *) p_PosReq := TRUE; (* 上升沿触发定位指令 *) timeOutCnt := 0; state := 31; END_IF; 31: (* 等待定位完成 *) timeOutCnt := timeOutCnt + 1; IF p_PosDone THEN (* 底层返回定位完成 *) p_PosReq := FALSE; o_Busy := FALSE; o_Done := TRUE; state := 0; ELSIF timeOutCnt > 30000 THEN (* 超时报警 *) p_PosReq := FALSE; o_Error := TRUE; o_ErrorID := 16#1103; state := 0; END_IF;定位运动这里有一个容易被忽略的点:绝对定位的目标位置单位是脉冲,而不是毫米或度。如果触摸屏上操作员输入的是毫米数,上位机程序或FB块内部必须乘上电子齿轮比换算成脉冲。模板程序在接口注释里明确写了「单位:脉冲」,这是故意的——把单位换算放在FB块外面,FB块内部只做脉冲级的定位逻辑,换算关系改动时不用动状态机。
定位状态里的超时时间我给了30秒的扫描计数偏长,实际项目里要根据行程和速度计算。一个更稳妥的做法是让上位机在下发定位指令时同时给出一个期望完成时间,FB块拿这个时间做超时阈值,这样同一个FB块可以适应快速小行程和慢速大行程两种工位。
3.5 多轴实例化:主程序里六个轴的调用方式
轴FB块写完之后,主程序里的使用非常简单。建六个FB实例,每个实例对应一个物理轴,调用时把各自的全局标签接到接口上。这里用三菱ST的FB调用语法,输入参数用「:=」赋值,输出参数用「=>」带回。
(* 主程序中实例化六个轴 *) fb_XAxis : Fb_Axis; (* X轴实例 *) fb_YAxis : Fb_Axis; (* Y轴实例 *) fb_ZAxis : Fb_Axis; (* Z轴实例 *) fb_U_Axis : Fb_Axis; (* U轴实例 *) fb_V_Axis : Fb_Axis; (* V轴实例 *) fb_W_Axis : Fb_Axis; (* W轴实例 *) (* 每个扫描周期调用一个轴实例 *) fb_XAxis(i_Enable := b_PowerOn, i_Command := n_XCmd, i_TargetPos := wn_XPos, i_Speed := wn_XSpeed, i_AccelTime := wn_XAccTime, i_DecelTime := wn_XDecTime, o_Busy => b_XBusy, o_Done => b_XDone, o_Error => b_XError, o_ErrorID => w_XErrID); fb_YAxis(i_Enable := b_PowerOn, i_Command := n_YCmd, i_TargetPos := wn_YPos, i_Speed := wn_YSpeed, i_AccelTime := wn_YAccTime, i_DecelTime := wn_YDecTime, o_Busy => b_YBusy, o_Done => b_YDone, o_Error => b_YError, o_ErrorID => w_YErrID);这段调用代码本身没有复杂逻辑,但它体现了FB块复用的价值:六个轴的内部状态机代码完全一样,每个实例只通过接口上的标签和外部交互。n_XCmd、wn_XPos这些全局标签可以从触摸屏或上位机直接写入,PLC侧的梯形图程序也可以通过M软元件赋值给这些标签。以后新增一个轴,复制这一段调用,改个实例名和标签名就行。
这里有一个工程习惯值得养成:六个轴的实例名、标签名严格按轴号命名,X、Y、Z、U、V、W对应设备坐标系,触摸屏画面上的轴名称和PLC标签保持一致。设备调试时,程序里看到fb_XAxis就知道是X轴,w_XErrID能直接在监视窗口里查故障,省去翻图纸对照软元件表的功夫。
4. 工程落地:GX Works3里把ST轴FB块跑起来的完整步骤
4.1 新建工程与ST程序语言设置
GX Works3里新建工程时,系列选MELSEC iQ-F,机型选对应的FX5U CPU型号,程序语言这一栏选结构化文本ST。如果主程序之前已经用梯形图写好了,也不用重建工程,直接在工程树里右键「程序」新建一个ST程序块,把轴FB块的调用代码放进去。FB本体放在工程树的「功能块」下,右键新建FB,语言也选结构化文本。
把3.1的接口声明和状态机代码粘贴到FB编辑器里后,先单独编译FB,确认没有语法错误,再编译整个工程。FB块编译通过后会出现在功能块列表里,主程序实例化时能直接选择。这里有一个容易踩的步骤:如果先编译整个工程再回头改FB,GX Works3有时候不会自动刷新FB的接口变化,会报「FB调用与接口不一致」。我一般习惯先编译FB,再编译全部程序,两次编译都过了再写入PLC。
4.2 FB块的编译错误排查与程序写入
ST代码的编译错误大多集中在三处:变量名拼写不一致、指令对操作数类型有要求、标签名重复定义。GX Works3的错误窗口会定位到具体行号,比如「标签未定义」会直接指向代码里出错的那一行。还有一种常见错误是FB实例化后接口参数类型不匹配,比如i_TargetPos是DINT,标签用了INT,编译报「数据类型不一致」。
注意:RUN状态下写入程序会让CPU瞬时停机,伺服轴会丢掉使能,设备在自动运行中容易出事故。批量调试时先切STOP再写入程序,写完后切RUN,这是基本操作顺序。
写入前建议把PLC的RUN开关切到STOP,程序写入完成后再切回RUN。第一次写入后,务必做一次断电重启,确认FB块的初始值逻辑正常。如果上电后轴自己动了一下,多半是内部变量没有初始化或者输出没有初值,回到3.1把VAR区变量的初始值检查一遍。
4.3 轴参数与软元件分配参考表
模板程序里轴参数分成两类:一类是FB块接口上的输入参数,可以在触摸屏上随时改;另一类是底层驱动信号,需要按实际接线分配到软元件。下面是参考分配表,实际项目按设备的电气图纸调整。
| 参数 | 标签或软元件 | 典型值 | 说明 |
|---|---|---|---|
| 指令号 | n_XCmd | 0~4 | 触摸屏/上位机写入 |
| 目标位置 | wn_XPos | 0 | 单位脉冲,需换算 |
| 运行速度 | wn_XSpeed | 100000 | 脉冲/秒 |
| 加速时间 | wn_XAccTime | 100 | 毫秒 |
| 减速时间 | wn_XDecTime | 100 | 毫秒 |
| 原点复归请求 | p_HomeReq | 无 | FB内部转到底层DRVZ触发 |
| 原点复归完成 | p_HomeDone | 无 | 限位信号映射 |
| 正转点动 | p_JogDir=0 | 无 | 驱动层的方向软元件 |
| 定位完成 | p_PosDone | 无 | 底层指令完成标志 |
分配软元件时有一个原则:输入输出信号用全局软元件或全局标签,FB内部状态变量用局部VAR,不要混用。p_开头的底层信号在模板里是FB内部标签,但它们最终要映射到物理输入点或中间继电器,这部分映射放在底层驱动程序里单独维护,不在FB块内部写死。
4.4 在线监视与调试
程序写入后,打开在线监视,把state变量拖进监视窗口。如果轴点了定位没反应,看state卡在哪个值:卡在30说明定位参数缓存阶段就卡住了,优先查i_Command有没有正确写入;卡在31说明指令已经发出,但底层p_PosDone一直没返回,这时候查伺服驱动器有没有报警、脉冲线是不是松了、方向的软元件映射对不对。
调试原点复归时,我最常干的一件事是把p_HomeReq和p_HomeDone同时拉进监视窗口。按下原点复归按钮,p_HomeReq变TRUE,如果几秒后p_HomeDone还是FALSE,基本可以判断是限位开关信号没到,用万用表量输入点之前先看监视窗口,能省不少跑上跑下的功夫。state变量加一个D区镜像值,让触摸屏把当前状态码显示出来,设备交到现场之后,操作工报「走不了」时直接看屏幕状态码,比拿电脑连PLC快得多。
5. 避坑:FX5U轴FB块开发中四个典型的翻车现场
5.1 定位指令被重复触发,轴走一段停一段
现象:i_Command保持4不变,定位指令发出后轴确实在走,但走一段停一下,停一会儿又继续走,最终位置不对,伺服偶尔还会报警。
原因:DRVZ和定位指令本质上是上升沿触发。梯形图里指令由条件接点触发,一次扫描只执行一次;在ST的状态机里,如果直接用IF i_Command = 4这种写法写在主循环里,每个扫描周期条件都成立,底层指令就被反复触发。轴走一段停一下,实际是上一次定位被新的触发打断,重新再走。
解决:FB块入口处做指令沿检测,就是3.1里那段IF i_Command <> edgePrevCmd。只有指令号发生变化的那一个扫描周期才允许进入新的状态机分支,进入后只发一次请求,剩下的时间都停在等待完成状态。
5.2 多实例共用M线圈,六个轴一动全动
现象:第一个轴调试正常,复制出第二个轴实例后,点动第一个轴时第二个轴也跟着动,两个轴的限位信号互相干扰,原点复归完全乱套。
原因:FB块内部用了M100、M101这类全局软元件做中间信号。FB块代码只写一份,实例化六份后,六个实例操作的是同一个M线圈,互相踩踏。我拆过不少项目,这种问题最容易出现在从梯形图程序改成FB块的过程中——梯形图习惯用M软元件做中间继电器,写ST时顺手就用了。
解决:FB块内部所有中间变量全部改成VAR局部变量,FB块本体代码里不允许出现任何M开头或D开头的全局软元件。确实需要和外部交互的信号,走接口参数和p_底层映射,每个实例通过不同的接口标签区分。检查办法很简单:编译前搜一遍FB源码,M和D开头的基本可以判死刑。
5.3 原点复归一启动就往反方向跑
现象:按下原点复归按钮,轴直接向远离原点开关的方向加速,直到撞上硬限位触发报警。
原因:DRVZ回原点的搜索方向和机械结构有关,模板默认了一个搜索方向,实际设备的原点开关装在丝杠另一侧时,方向就是反的。另外,如果轴在原点开关的同侧,回原点的动作会先离开原点再反向搜索,逻辑上是对的,但现场看着就像「往反方向乱跑」。这个问题属于机械与程序配置不匹配,不是代码错误。
解决:把原点搜索方向做成一个配置参数,我在实际项目里把p_HomeMode扩展成两个值:0表示正向搜索原点,1表示反向搜索原点。首次调试时先手动点动把轴移动到原点开关附近,再执行原点复归,确认动作方向正确后把这个参数固定下来。改方向时只需要改一个配置点,不要去动状态机代码。
5.4 ST里复制过来的定位指令编译报错
现象:从手册或旧工程里复制一段定位指令到ST编辑器,编译报错,错误信息指向指令名称或操作数类型不兼容。
原因:三菱ST对定位指令的调用格式有限制,部分指令不能在ST的CASE分支里直接写成指令形式,有的需要先通过MOV把参数搬到指定的软元件区,再通过专用的触发条件启动。不同固件版本对指令的支持程度也不一样,直接复制很容易踩坑。
解决:统一走模板里分层的做法,定位指令只出现在底层驱动块里,上层状态机不直接接触指令。底层驱动块把p_PosCmd、p_VelCmd这些参数先缓存到对应轴专用的D区软元件,再给触发信号一个上升沿。这样做除了避开编译限制,还带来一个额外好处:如果以后换了CPU型号,只需要重写底层驱动块,状态机部分可以整体迁移。
6. 二次开发:一台设备挂八个轴,怎么把FB块的复用价值榨干
6.1 用结构体数组管理轴参数
当设备从六轴变成八轴,每个轴还要配原点方向、软限位、点动速度、单独的超时时间,接口参数会越来越多。与其每个轴写一行冗长的FB调用,不如定义结构体数组,把轴参数集中到一个数据块里管理。
TYPE AXIS_PARAM : STRUCT Speed : DINT; (* 定位速度 *) JogSpeed : DINT; (* 点动速度 *) AccelTime : INT; (* 加速时间 *) DecelTime : INT; (* 减速时间 *) HomeDir : BOOL; (* 原点搜索方向 *) SoftLimitMin : DINT; (* 软限位下限 *) SoftLimitMax : DINT; (* 软限位上限 *) END_STRUCT; END_TYPE VAR AxisParam : ARRAY[0..7] OF AXIS_PARAM; AxisFB : ARRAY[0..7] OF Fb_Axis; END_VAR初始化时给每个数组元素赋不同的速度、软限位值,调用时用FOR循环统一执行FB实例,代码量比八个轴的梯形图少一个数量级。数据块里的参数可以直接映射触摸屏,操作工在画面上改速度,PLC程序下次扫描自动生效。这是把模板程序改成真正多轴设备程序的必经一步。
6.2 加软限位与寸动速度分档
模板程序里的软限位检查已经留了接口位置,二次开发时把3.4里那个写死的100000000换成结构体数组里的SoftLimitMin和SoftLimitMax。每次进入定位状态前判断目标位置是否在限位区间内,超出直接报错,不给底层指令。在自动运行模式里,软件限位比硬限位开关反应更快,能少撞几次设备。
寸动速度分档的做法是给i_Command复用更多指令号:5表示低速点动正转,6表示低速点动反转。在状态机入口判断指令号,点动状态里按指令号选择低速或者高速路径,速度值从结构体数组里取。分档点动主要用在手动装配对位场景,低速档能帮操作工精确对准位置。
6.3 触摸屏标签映射与完成信号锁存
FB块的接口要做成全局标签,触摸屏才能直接读写。三菱触摸屏软件里可以直接关联GX Works3的全局标签,但现场有时候会遇到只有D区软元件可用的旧触摸屏,这就需要把FB块的输入输出和D区软元件做一个映射层。我习惯在程序里单独写一小段ST,专门做标签到D区的搬运,每个轴固定一段D区地址,轴号、位置、速度、状态码一目了然。
o_Done完成信号还有一个细节:它是一个扫描周期的脉冲,触摸屏上如果用它去翻页或弹窗,经常因为太短抓不到。在实际项目里,我会在FB块外部把o_Done锁存到一个全局标签里,由触摸屏的「确认」按钮复位。从那以后我每次加新轴,都强制走一遍完整流程:确认FB实例名命名规范、检查内部变量没有全局软元件、核对软限位和超时参数、锁存完成信号——这套模板才算是真正吃透了,希望帮到你。
本文还有配套的精品资源,点击获取