NC

用户宏程序与子程序入门:用实例和图解学 M98、M99、G65、#变量、IF、WHILE

写一次,改个尺寸就能反复调用。先从 M98 和 G65 的区别看起吧!

吉祥物 Chips
用户宏程序与子程序入门:用实例和图解学 M98、M99、G65、#变量、IF、WHILE

形状相同只是尺寸不同的零件、分布在圆周上的螺栓孔、反复出现的槽……这类加工,你是否每次都用 CAM 或手算重新编程?NC 中有能把程序的一部分调用并重复执行的“子程序”,以及可以使用变量、计算和条件分支的“用户宏程序”(有些厂家称为用户宏、宏程序 B(Macro B)等)。本文用动作示意图和程序示例依次讲解 M98、M99、G65、#变量、IF、WHILE,最后还可以用计算器试用螺栓孔圆(分布圆孔)宏程序。

主程序 O1000#1=500.G00 X#1→ X500.M98 P1100G00 X#1→ X700.(子程序改写了 #1)G65 P9100 A600.G00 X#1→ X700.(宏程序中的 #1=800. 不影响)M30子程序 O1100#1=700.G00 X#1M99→ X700.宏程序 O9100G00 X#1→ X600.#1=800.M99调用用 M99 返回用 M98 调用时#1~#33 与调用方共用同一组变量在内部改写后,即使返回值仍保持改变不能传递自变量用 G65 调用时#1~#33 变为新的一组像 A600. → #1 这样可用自变量传值返回后恢复原来的 #1未写的自变量为“空”
M98(子程序)与 G65(宏程序)的区别。在 M98 调用的程序中改写 #1,主程序的 #1 也会改变。G65 调用的程序中的 #1 是另一个变量(依据 Haas 使用说明书的说明)[1]。

子程序和宏程序能让哪些工作变轻松

  • 重复相同的动作:等间隔的槽、形状相同的型腔,只写一处,反复调用(子程序)
  • 把尺寸不同的零件合为一个程序:用“自变量”传入直径、深度、孔数,一个程序就能加工不同型号(宏程序)
  • 自制固定循环:把螺栓孔圆、角度排列孔、端面铣的往复走刀等做成像 G81 那样一行就能调用的形式[1][6]
  • 测量与管理:用测头测得的值修正补偿,统计加工件数后停机,统计刀具使用次数[1][10]

宏程序在研究中也有应用。已有报告提出:把从 3D 模型读取的形状尺寸送入宏程序的自变量、不用 CAM 即可生成加工程序的系统[14],以及不制作专用成形车刀、用普通切槽刀片和宏程序车削非对称梯形螺纹(锯齿形螺纹)的方法[15]。两者都发挥了宏程序“改尺寸只需改自变量”的长处。

在有些 NC 上,用户宏程序是选配功能,可用的变量范围也因机型和选项而异。本文的写法以 FANUC 兼容写法(即所谓宏程序 B)为准,机型不同的地方都随处注明。由于 FANUC 的使用说明书不对外公开,本文内容是根据公开的 Haas、Siemens(ISO 方言模式)、Tornos 等资料确认的。使用前请务必查阅自己机床的说明书。

子程序:用 M98 调用,用 M99 返回

子程序的机制是:把加工内容写在另一个程序号中,用 M98 调用,最后用 M99 返回调用方的下一行[4][5]。

写法含义机型差异
M98 P1100调用 O1100 一次—
M98 P51100调用 O1100 五次(P 的后 4 位是程序号,前面的位是次数)FANUC 兼容写法。Siemens ISO 方言模式的说明书中也相同(例:M98 P30021 调用 21 号程序 3 次)[7]
M98 P1100 L5调用 O1100 五次(用 L 指定次数)Haas 采用这种写法(L 为 1~99)[4]
M97 P100调用同一程序中从 N100 开始的部分Haas 的本地子程序。放在 M30 之后,以 M99 结束[3]
M99返回调用方的下一行在主程序中执行时,返回开头重复执行(直到复位)[5][12]
M99 P50返回调用方的 N50返回目标的搜索方向(向前、向后)因机型而异[7]

示例:切 5 条等间隔的槽

如果子程序内部用增量(G91)编写,每次调用都会在逐步错开的位置上执行相同的动作。要点是最后 先切回 G90,再 用 M99 返回。

O1000 (MAIN)
G90 G17 G40 G49 G80
G54
T01 M06                (φ10 立铣刀)
S2000 M03
G00 X0. Y-10.
G43 Z50. H01 M08
Z2.
M98 P51100             (O1100 调用 5 次;Haas 用 M98 P1100 L5)
G90 G00 Z50. M09
G91 G28 Z0.
M30

O1100 (SLOT 1 PITCH)
G91 G00 X15.           (横移 15 mm)
G01 Z-7. F100          (从 Z2. 下降 7 mm 到 Z-5.)
Y40. F200              (切槽 40 mm)
G00 Z7.                (返回 Z2.)
Y-40.                  (返回槽起点)
G90                    (切回绝对值后返回)
M99
12345起点 X0. Y-10.(槽的前方)15M98 P51100 → 每调用一次 X 前进 15 mm
俯视图(尺寸未按比例)。第 1 次调用在 X15. 处切第 1 条槽,第 5 次在 X75. 处切第 5 条槽。

不要在 G91 状态下返回如果在子程序中切换到 G91 后直接用 M99 返回,主程序中返回后的下一行会按增量移动,跑到意想不到的位置。像本例这样在子程序末尾切回 G90,并在主程序返回后的下一行也写上 G90,就是双重保险。

变量:用 #编号存放数值

在宏程序中,像 #1=100. 这样用“#”加编号来表示变量,写成X#1 就会按 X100. 运行。不同的编号范围承担不同的作用。

编号类型内容、用法机型差异
#0空(空变量)不含值的特殊变量。只能读取,不能赋值。用#1=#0 可将 #1 恢复为空Haas、Tornos、MachMotion 通用[1][8][9]
#1〜#33局部变量只在该程序内部使用。用 G65 调用时会新建一组,并存入自变量的值Siemens 的 ISO 方言模式不用 #1~#33,而是用 $C_A~$C_Z 这些另外的变量接收自变量[7]
#100〜#199
#500〜#999
公共变量任何程序都能看到相同的值。用于在调用之间传递数值,或统计加工件数断电后是否保留因机型而异。Haas 两者都保留[1],MachMotion 每次启动都会清除 #100 段[9]。可用范围也因选项而异
#1000〜系统变量读写 NC 内部的数据,如刀具补偿量、工件坐标系、计时器、报警等编号分配因机型差异很大。例如 Haas 的 #2001~ 为刀具长度补偿,#3001 为毫秒计时器,#3011 为年月日[1]

使用公共变量前先确认编号“空闲”#500 段等公共变量,有时测头、托盘交换等机床厂家内置的程序也在使用。Haas 的说明书提醒:覆盖测头的校准值(#550~#599)后需要重新校准[1]。新使用之前,请在说明书和变量画面上确认空闲的编号。

“空”和“0”不同

用 G65 调用宏程序时,新的局部变量全部变为空,只有调用行中写了地址的对应变量才会存入值[1]。也就是说,漏写的自变量不是 0,而是空。空变量用作坐标时,该轴的指令可能被忽略而“不动”;用于计算时可能被当作 0(具体处理请查阅机型说明书)。因此,通常先对重要的自变量像 IF [#11 EQ #0] GOTO 900 这样检查是否为空,为空就用报警停机,这是常用做法[10][9]。

LinuxCNC(RS274NGC 系)没有“空”,未传入的自变量为 0[11]。若把 FANUC 兼容的宏程序直接搬过去,空值判断将不起作用,请注意。

计算:四则运算与函数

变量中可以存入计算结果。运算顺序用 [ ](方括号)来决定(圆括号 ( ) 是注释,不能使用)。Haas 的例子中, [3*[9+3]] 的结果为 36[6]。

写法含义备注
#3=#1+#2 - * /四则运算先乘除,后加减
SIN[#1] COS[#1] TAN[#1]三角函数角度单位是“度”(不是弧度)[8][11]
ATAN[#1]/[#2]反正切(由两个值求角度)写法(/ 或 ,)和结果范围因机型而异[13]
SQRT[#1] ABS[#1]平方根、绝对值—
ROUND[#1] FIX[#1] FUP[#1]四舍五入、舍去、进位(取整)负数的取整方式因系统而异(LinuxCNC 的 FIX[-2.8] 为 -3)[11]
EQ NE GT LT GE LE比较:= ≠ > < ≥ ≤用于 IF、WHILE 的条件[1][8]
AND OR XOR逻辑运算组合多个条件[8][13]

不要用“相等”比较小数计算出的值可能含有 0.0000001 这样的误差,导致 EQ 不成立。Haas 的说明书建议在比较前先用 ROUND 取整[1]。用于统计循环次数的变量,用整数计数比较安全。

G65:传递自变量调用宏程序

G65 :像G65 P9100 X0. Y0. D100. H6. 这样带上字母自变量来调用宏程序。P 为程序号,L 为次数,其他地址的值存入局部变量[2][1]。哪个字母存入哪个变量是固定的(自变量指定 I),G、L、N、O、P 不能用作自变量。

A#1
B#2
C#3
D#7
E#8
F#9
G×
H#11
I#4
J#5
K#6
L×
M#13
N×
O×
P×
Q#17
R#18
S#19
T#20
U#21
V#22
W#23
X#24
Y#25
Z#26
自变量指定 I 的对应关系(Haas、Tornos、MachMotion 的资料一致)[1][8][9]。灰色的 G、L、N、O、P 不能使用。另有把 I、J、K 重复排列多组的“自变量指定 II”,可以给 #1~#33 全部传值。

字母顺序与变量编号并不一致的地方(I=#4、D=#7、H=#11 等)容易弄错,因此在宏程序开头用注释写明“哪个自变量用作什么”,以后阅读的人会轻松很多。自变量指定 I 中不会存入值的 #10、#12、#14、#15、#16、#27、#28、#29、#30、#31、#32、#33 ,可在宏程序中用来存放计算的中间结果。

自变量要带小数点没有小数点的自变量,可能按最小单位读取。Haas 的说明书中,在公制设定下写 A1 时,#1 不是 1,而是 0.001 (D、E、F、H、L、M、S、T 除外)[1]。在 Siemens 的 ISO 方言模式中,无小数点数值的读法也随机床设定而变[7]。A1. 这样,自变量务必带上小数点。

与 M98 的区别,以及 G66(模态调用)

  • 自变量:G65 可以传递,M98 不能(要传值时使用公共变量)[1][7]
  • 局部变量:G65 每次调用都会新建一组,返回后恢复原值。M98 直接使用与调用方相同的变量[1]
  • G66:G66 P_ 自变量 … 之后,每执行完一个移动指令就调用一次宏程序。用法是只列出孔的位置,每次都运行同一个加工宏程序。用G67 取消[7][10]

IF、GOTO、WHILE:分支与循环

写法动作
GOTO 100跳转到 N100 行(无条件)
IF [#1 GT 10.] GOTO 100仅当 #1 大于 10 时跳转到 N100
IF [#1 GT 10.] THEN #1=10.仅当条件成立时,执行后面的一条语句(有些老式 NC 不能用 THEN)[8][10]
WHILE [#1 LT 5] DO 1
 …
END 1
条件成立期间,重复执行 DO 1 到 END 1 之间的内容[6][8]
○ 可以嵌套(最多 3 层)× 不能交叉× 不能从外部跳入内部○ 可以从内部跳出WHILE[…] DO 1WHILE[…] DO 2…END 2END 1WHILE[…] DO 1WHILE[…] DO 2END 1END 2GOTO 10WHILE[…] DO 1N10 …END 1WHILE[…] DO 1IF[…] GOTO 10END 1N10 …内层完全包在外层中END 1 位于 DO 2 内不要跳到循环内的 N 号需要中途退出时使用
DO 与 END 的编号(1~3)要对应,重叠时要把内层完全包在外层中。最多 3 层嵌套依据的是搭载 FANUC 系统机型的公开资料(Tornos)[8]。循环结束后,同一编号可以再次使用。

用报警停机:#3000

发现漏写自变量或不可能的值时,像#3000=1 (H WO KAKU) 这样 给 #3000 赋一个编号使机床停止。Haas 中会变为编号加 1000 的报警(#3000=1 即 1001),括号中的注释会显示在画面上[1]。显示方式因机型而异,但作为宏程序的安全装置,在任何机型上都是常用做法[8][10]。

编号相近的 #3006(显示信息并停止)在不同机型上动作各不相同:“暂停并等待重新启动”、“只显示信息而不停止”、“需要复位的报警”[1][8][9]。使用前务必查阅说明书确认。

示例:螺栓孔圆(PCD)宏程序

这个宏程序只需传入中心、PCD、孔数、起始角度,就能钻出在圆周上等间隔分布的孔。内部用 WHILE 按孔数循环,用 COS、SIN 计算各孔的 X、Y,再用 G81 钻孔。Haas 的说明书中也有思路相同的“斜向一排钻孔宏程序”的例子[1]。

(调用侧:先完成换刀、主轴旋转和 G43)
G65 P9100 X0. Y0. D100. H6. A0. Z-15. R3. F150.

O9100 (BOLT HOLE CIRCLE)
(X=#24 Y=#25 中心  D=#7 PCD  H=#11 孔数)
(A=#1 起始角度  Z=#26 孔底  R=#18 R点  F=#9 进给)
IF [#7 EQ #0] GOTO 901          (PCD 为空则停止)
IF [#11 EQ #0] GOTO 902         (孔数为空则停止)
IF [#1 EQ #0] THEN #1=0.        (省略角度则从 0 度开始)
#27=0                           (当前第几个孔)
#28=360./#11                    (孔间角度)
WHILE [#27 LT #11] DO 1
  #29=#1+#27*#28                (本孔角度)
  #30=#24+#7/2*COS[#29]         (本孔 X)
  #31=#25+#7/2*SIN[#29]         (本孔 Y)
  G90 G99 G81 X#30 Y#31 Z#26 R#18 F#9
  #27=#27+1
END 1
G80
M99
N901 #3000=1 (PCD D MISSING)
N902 #3000=2 (HOLE COUNT H MISSING)

局部变量中,自变量指定 I 不会存入值的 #27〜#31 被用作计算的存放处。角度从 X 轴正方向起按逆时针计,以度为单位计算。孔与孔之间有压板时,请把 G99 改为 G98,退回到初始点(参见固定循环一览中的 G98、G99)。

不要直接运行此程序只是写法示例。有的 NC 不能用 THEN,有的变量范围或 #3000 的写法不同。输入机床后,请先用单段、空运行(抬起 Z 的状态)逐孔确认位置,并在变量画面上确认 #29~#31 的值与计算一致,然后再加工。在像 Haas 这样通过预读提前完成运算的 NC 上,夹有输出开/关的宏程序可能无法按预期动作(Haas 用 G103 P1 限制预读)[1][6]。

计算器:确认宏程序输出的孔坐标

用与上面宏程序相同的计算,输出各孔的 X、Y 和调用行。请在运行到机床之前用于验算。如果只想由 PCD 求孔坐标,也有 PCD 计算器可用。

孔角度(#29)X(#30)Y(#31)

#28 = 360 ÷ 孔数 #29 = 起始角度 + (孔号 − 1) × #28 X = 中心 X + PCD ÷ 2 × cos #29 Y = 中心 Y + PCD ÷ 2 × sin #29(角度从 X 轴正方向起按逆时针计)

常见的 8 种失误

  1. 忘记给自变量加小数点:Z-15 在有些机型上会被读成 -0.015。自变量应写成 Z-15. 的形式[1]
  2. 弄错自变量的字母:I 是 #4,D 是 #7,H 是 #11。字母顺序与编号并不一致
  3. 试图把 G、L、N、O、P 用作自变量:P 会被读作程序号,L 会被读作次数
  4. 在用 M98 调用的程序中改写局部变量:调用方的 #1~#33 也会改变。若要保护数值,请用 G65 调用
  5. 子程序在 G91 状态下退出:返回后会按增量移动。请在 M99 之前切回 G90
  6. 公共变量与其他程序冲突:覆盖了测头或机床厂家宏程序正在使用的编号[1]
  7. 用 EQ 比较小数:因计算误差而不成立。请先用 ROUND 取整,或用整数计数[1]
  8. WHILE 的结束条件始终不成立:忘记递增计数变量会造成死循环。一开始请用单段运行确认

常见问题

用户宏程序在所有 NC 上都能用吗?
很多 NC 上这是选配功能,没有安装时 G65 和 #变量会报警。可用的变量范围也因选项而异。另外,Siemens 在 ISO 方言模式(FANUC 兼容模式)下接受 G65,但接收自变量的变量不是 #1~#33[7]。请先确认自己机床的规格和说明书。
子程序中还能再调用子程序吗?
可以(多重调用、嵌套)。但能嵌套几层因机型而异,Siemens ISO 方言模式的 M98 视版本为 4 层或 16 层[7],LinuxCNC 为 10 层[12]。这与 WHILE 的嵌套(最多 3 层)是不同的上限。
主程序的最后写 M99 会怎样?
会回到开头重复执行(直到复位)。常用于反复进行暖机运转[5][12]。加工零件时请注意不要忘记停止。
能把宏程序作为自己的 G 代码或 M 代码来调用吗?
很多 NC 可以通过参数设置,用特定的 G、M 代码调用宏程序。Haas 可把 O9010~9019 分配给 G 代码,O9000~9009 分配给 M 代码,用 G 代码调用时可以传递自变量[1]。FANUC 的培训中也讲到 G102 这样的自定义 G 代码,以及用 M、T 代码调用宏程序。[10]。

各 G、M 代码的含义汇总在 G、M 代码词典,钻孔固定循环汇总在 固定循环一览一文中。

参考资料

  1. Haas Automation「Mill Operator's Manual 13 - Macros」
  2. Haas Automation「G65 Macro Subprogram Call」
  3. Haas Automation「M97 Local Subprogram Call」
  4. Haas Automation「M98 Subprogram Call」
  5. Haas Automation「M99 Subprogram Return or Loop」
  6. Haas Automation“Macro Programming Information”(PDF)
  7. Siemens“SINUMERIK ISO Milling Programming Manual”(ISO 方言,2007)
  8. Tornos“Tips & Tricks: B Macro – ISO machines”(PDF)
  9. MachMotion「Macro B Reference Guide」
  10. FANUC eACADEMY“在线点播讲座 CNC 用户宏程序”(课程介绍,日文)
  11. LinuxCNC“G-code Overview”(参数、表达式、函数)
  12. LinuxCNC“O Codes”(子程序、M98/M99)
  13. NIST“The NIST RS274NGC Interpreter – Version 3”(NISTIR 6556)
  14. Nguyen, Phung, Bui“Novel Integration of CAPP in a G-Code Generation Module Using Macro Programming for CNC Application”Machines 8(4), 61(2020)
  15. Kasabov 等“A Parametric CNC Approach for Buttress Thread Machining”Engineering Proceedings 150, 91(2026)

更多文章