Files
weinviews-unitouch/设计文档/宏指令.md
T

1140 lines
85 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 宏指令(全部,逐行注释)
> 摘自同目录 `开发主文件.md` 第 6 章,直接复制到 EB Pro 宏编辑器。
## 6.0 工程实际清单(2026-10-27 核对,依据 EB Pro「宏指令」窗口)
> 现工程 `unitouch1025.cmtp` 共 **50 条**(ID 000~050,**缺 031**)。
> `{I}` = 当 HMI 启动时即执行一次;`{P}` = **周期执行**;无标记 = 由按钮/窗口事件触发。
> 本表是“以工程为准”的基准,下文 6.1 起的正文若与本表冲突,**以本表为准**。
| ID | 宏名 | 条件 | 用途 | 文档状态 |
|---|---|---|---|---|
| 000 | `main-init` | I | 开机初始化 `LW-0/1/2`、页面位图 `LW-70~73`、`RW-61` | 有正文 |
| 001~007 | `btn-y1`~`btn-y7` | — | Y 页签导航(权限 + 页面存在位图) | 有正文 |
| 008~011 | `btn-x1`~`btn-x4` | — | X 页签导航 | 有正文 |
| 012 | `btn-login-index` | — | 索引登入 + 内联提示映射 | 有正文 |
| 013 | `macro_13` | — | **未命名宏**,疑似废弃残留 | **未记录** |
| 014 | `close-msg` | — | 关 11 号无权限窗 | 有正文 |
| 015~017 | `open-time` / `set-time` / `close-time` | — | 修改时间 | 有正文 |
| 018 | `logout` | — | 注销并回 10 号窗 | 有正文 |
| 019 | `user-open` | — | 开 14 号用户管理窗 | 有正文 |
| 020~027 | `usr-init`/`usr-back`/`usr-add`/`usr-delete`/`usr-delete-ok`/`usr-delete-cancel`/`usr-setlevel`/`usr-setpwd` | — | 用户管理各种命令 | 有正文(模板) |
| 028~029 | `about-open` / `about-close` | — | 关于窗 | 有正文 |
| 030 | `usr-getlevel` | — | 按索引读权限 | 有正文(模板) |
| — | (031 已删除,工程内无此 ID) | — | — | — |
| 032 | `close-nopage` | — | 关 16 号“无内容”窗 | 有正文 |
| 033~035 | `admin-close` / `admin-login` / `admin-open` | — | 超管登录弹窗 | 有正文 |
| 036 | `line-ab-switch` | — | A/B 线切换(仅 role=1) | 有正文 |
| 037 | `net-apply` | I | 网络参数套用(HMI + 设备 4/5 IP) | 有正文(10-27 已加 IP 保护) |
| 038 | `net-read` | — | 系统网络值 → 暂存 `RW` | 有正文 |
| 039~041 | `x2y2-focus-area1`~`area3` | — | X2Y2 三区聚焦 → `LW-50` | **正文缺失**(旧文档写作 `area-1~3`,名字已不符) |
| 042 | `IO切换上料` | — | 待确认(疑似 IO 监控页切换) | **未记录** |
| 043 | `x2y2-focus-area-close` | — | 关区域弹窗(`LW-50=0`) | **正文缺失**(旧文档写作 `area-close`) |
| 044 | `IO切换清洗` | — | 待确认 | **未记录** |
| 045 | `IO切换制丸` | — | 待确认 | **未记录** |
| 046 | `上料参数` | — | 待确认 | **未记录** |
| 047 | `温度监控` | P | 周期采集/判断温度 | **未记录** |
| 048 | `屏蔽通讯异常提示` | P | 周期置 ON `LB-11960~11967`(设备 1~8 的 “Device No Response”) | **未记录**(旧文档只提 11963/11964) |
| 049 | `出条温度监控` | P | 周期监控出条温度 | **未记录** |
| 050 | `IO` | — | 待确认 | **未记录** |
### 6.0.1 与旧文档的差异(已确认)
1. **区域弹窗宏名不对**:实际是 `x2y2-focus-area1~3` + `x2y2-focus-area-close`,旧文档的 `area-1~4` / `area-close` 作废;且**只有 3 个区域**,没有 area-4(与“4 区并 3 区”一致)。
2. **48 号宏 `屏蔽通讯异常提示` 是周期执行(P)**,不是开机一次;它把 `LB-11960~11967` 八台设备全屏蔽,不是文档写的 63/64 两台。
3. **7 条宏文档完全没有**:`macro_13`、`IO切换上料`、`IO切换清洗`、`IO切换制丸`、`上料参数`、`温度监控`、`出条温度监控`、`IO`(含 3 条周期温度宏)。
4. **ID 031 缺失**(工程里已删除,文档无记录)。
5. `macro_13` 未命名,建议确认是否可删。
### 6.0.2 待补正文(按优先级)
| 优先 | 宏 | 需要的确认 |
|---|---|---|
| 高 | `x2y2-focus-area1~3`、`-close` | ~~`LW-50` 是 30~32 还是 141~144~~ → **已确认 30/31/32**(工程窗口表) |
| 高 | `net-apply` | 新工程是否已含“IP 首段为 0 不覆盖”保护 |
| 中 | `IO切换上料/清洗/制丸`、`IO` | 是否属于 IO 监控页的页签切换,地址用哪批 |
| 中 | `上料参数` | 是否写 PLC 配方参数 |
| 低 | `温度监控`、`出条温度监控` | 周期时间、报警阈值地址 |
| 低 | `macro_13` | 是否废弃可删 |
## 6.1 宏正文(逐行注释)
> 命名:导航 = `btn-*`、登录 = `main-init`/`btn-login-index`/`logout`、管理员登录 = `admin-open`/`admin-login`/`admin-close`、用户管理 = `user-open` + `usr-*`(你的工程删除类为 `usr-delete*`)、关于窗 = `about-open`/`about-close`、时间 = `open-time`/`set-time`/`close-time`、弹窗 = `close-msg`/`close-nopage`。
> **登录提示已内联**:`LW-101` 结果码 → `LW-261` 的映射直接写在 `btn-login-index`/`admin-login` 内,零延迟、不轮询、不依赖宏编号。`net-apply` 用宏属性「当 HMI 启动时即执行一次」。
> 权限判定统一用 `LW-9222` 的类别位(`GETBIT` 取值 + `if`,不用 `and`/`&`)。
**`main-init`**(开机执行一次)
```
macro_command main() // 宏入口:HMI 启动时执行一次
short x = 1 // X 初值 = 1
short y = 1 // Y 初值 = 1
short win = 0 // 目标窗口号初值 = 0(不切窗)
short r1 = 127 // X1 段存在位图:bit0=Y1…bit6=Y7,1=有内容(X1 全有 = 127)
short r2 = 18 // X2 段:只留 Y2/Y5(缺 Y1/Y3/Y4/Y6/Y7)→ 2+16=18
short r3 = 127 // X3 段:Y1~Y7 全有(X3Y6 已启用)→ 127
short r4 = 18 // X4 段:只留 Y2/Y5(缺 Y1/Y3/Y4/Y6/Y7)→ 2+16=18
short one = 1 // 常量 1(默认制丸线别)
SetData(x, "Local HMI", LW, 0, 1) // X → LW-0
SetData(y, "Local HMI", LW, 1, 1) // Y → LW-1
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 0 → LW-2(不触发切窗)
SetData(r1, "Local HMI", LW, 70, 1) // X1 位图 → LW-70
SetData(r2, "Local HMI", LW, 71, 1) // X2 位图 → LW-71
SetData(r3, "Local HMI", LW, 72, 1) // X3 位图 → LW-72
SetData(r4, "Local HMI", LW, 73, 1) // X4 位图 → LW-73
SetData(one, "Local HMI", RW, 61, 1) // 开机默认制丸线别 = A(只有人工切换才变 B)
end macro_command // 宏结束
```
**导航宏说明**:先查权限(`LW-9222` 类别位)→ 再查当前 Y 页面是否存在(`LW-70`~`73` 位图)→ 有内容才切窗,无内容弹 16 号窗。
**`btn-x1`**(X1 配料/上料 · 权限 A/B/C)
```
macro_command main() // 宏入口:按下 X1 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 1 // 本按钮固定切到 X=1
short y = 0 // 运行时读回的当前 Y(1~7)
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // X1 段页面存在位图(LW-70)
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bC = 0 // 类别 C 位(上料)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bC, 2) // 取 bit2 → bC(C 上料)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if bC == 1 then // 含类别 C?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 继续查页面
GetData(y, "Local HMI", LW, 1, 1) // 读当前 Y → y
GetData(vpm, "Local HMI", LW, 70, 1) // 读 X1 段存在位图 → vpm
if y == 1 then // 当前 Y=1?
GETBIT(vpm, bv, 0) // 取位 0(Y1)→ bv
end if // 结束判断
if y == 2 then // 当前 Y=2?
GETBIT(vpm, bv, 1) // 取位 1(Y2)→ bv
end if // 结束判断
if y == 3 then // 当前 Y=3?
GETBIT(vpm, bv, 2) // 取位 2(Y3)→ bv
end if // 结束判断
if y == 4 then // 当前 Y=4?
GETBIT(vpm, bv, 3) // 取位 3(Y4)→ bv
end if // 结束判断
if y == 5 then // 当前 Y=5?
GETBIT(vpm, bv, 4) // 取位 4(Y5)→ bv
end if // 结束判断
if y == 6 then // 当前 Y=6?
GETBIT(vpm, bv, 5) // 取位 5(Y6)→ bv
end if // 结束判断
if y == 7 then // 当前 Y=7?
GETBIT(vpm, bv, 6) // 取位 6(Y7)→ bv
end if // 结束判断
if bv == 1 then // 该页面有内容?
SetData(x, "Local HMI", LW, 0, 1) // X=1 → LW-0
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-x2`**(X2 上料清洗 · 权限 A/B/C)
```
macro_command main() // 宏入口:按下 X2 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 2 // 本按钮固定切到 X=2
short y = 0 // 运行时读回的当前 Y(1~7)
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // X2 段页面存在位图(LW-71)
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bC = 0 // 类别 C 位(上料)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bC, 2) // 取 bit2 → bC(C 上料)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if bC == 1 then // 含类别 C?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 继续查页面
GetData(y, "Local HMI", LW, 1, 1) // 读当前 Y → y
GetData(vpm, "Local HMI", LW, 71, 1) // 读 X2 段存在位图 → vpm
if y == 1 then // 当前 Y=1?
GETBIT(vpm, bv, 0) // 取位 0(Y1)→ bv
end if // 结束判断
if y == 2 then // 当前 Y=2?
GETBIT(vpm, bv, 1) // 取位 1(Y2)→ bv
end if // 结束判断
if y == 3 then // 当前 Y=3?
GETBIT(vpm, bv, 2) // 取位 2(Y3)→ bv
end if // 结束判断
if y == 4 then // 当前 Y=4?
GETBIT(vpm, bv, 3) // 取位 3(Y4)→ bv
end if // 结束判断
if y == 5 then // 当前 Y=5?
GETBIT(vpm, bv, 4) // 取位 4(Y5)→ bv
end if // 结束判断
if y == 6 then // 当前 Y=6?
GETBIT(vpm, bv, 5) // 取位 5(Y6)→ bv
end if // 结束判断
if y == 7 then // 当前 Y=7?
GETBIT(vpm, bv, 6) // 取位 6(Y7)→ bv
end if // 结束判断
if bv == 1 then // 该页面有内容?
SetData(x, "Local HMI", LW, 0, 1) // X=2 → LW-0
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-x3`**(X3 制丸 · 权限 A/B/D)
```
macro_command main() // 宏入口:按下 X3 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 3 // 本按钮固定切到 X=3
short y = 0 // 运行时读回的当前 Y(1~7)
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // X3 段页面存在位图(LW-72)
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bD = 0 // 类别 D 位(制丸)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bD, 3) // 取 bit3 → bD(D 制丸)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if bD == 1 then // 含类别 D?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 继续查页面
GetData(y, "Local HMI", LW, 1, 1) // 读当前 Y → y
GetData(vpm, "Local HMI", LW, 72, 1) // 读 X3 段存在位图 → vpm
if y == 1 then // 当前 Y=1?
GETBIT(vpm, bv, 0) // 取位 0(Y1)→ bv
end if // 结束判断
if y == 2 then // 当前 Y=2?
GETBIT(vpm, bv, 1) // 取位 1(Y2)→ bv
end if // 结束判断
if y == 3 then // 当前 Y=3?
GETBIT(vpm, bv, 2) // 取位 2(Y3)→ bv
end if // 结束判断
if y == 4 then // 当前 Y=4?
GETBIT(vpm, bv, 3) // 取位 3(Y4)→ bv
end if // 结束判断
if y == 5 then // 当前 Y=5?
GETBIT(vpm, bv, 4) // 取位 4(Y5)→ bv
end if // 结束判断
if y == 6 then // 当前 Y=6?
GETBIT(vpm, bv, 5) // 取位 5(Y6)→ bv
end if // 结束判断
if y == 7 then // 当前 Y=7?
GETBIT(vpm, bv, 6) // 取位 6(Y7)→ bv
end if // 结束判断
if bv == 1 then // 该页面有内容?
SetData(x, "Local HMI", LW, 0, 1) // X=3 → LW-0
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-x4`**(X4 制丸清洗 · 权限 A/B/D)
```
macro_command main() // 宏入口:按下 X4 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 4 // 本按钮固定切到 X=4
short y = 0 // 运行时读回的当前 Y(1~7)
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // X4 段页面存在位图(LW-73)
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bD = 0 // 类别 D 位(制丸)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bD, 3) // 取 bit3 → bD(D 制丸)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if bD == 1 then // 含类别 D?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 继续查页面
GetData(y, "Local HMI", LW, 1, 1) // 读当前 Y → y
GetData(vpm, "Local HMI", LW, 73, 1) // 读 X4 段存在位图 → vpm
if y == 1 then // 当前 Y=1?
GETBIT(vpm, bv, 0) // 取位 0(Y1)→ bv
end if // 结束判断
if y == 2 then // 当前 Y=2?
GETBIT(vpm, bv, 1) // 取位 1(Y2)→ bv
end if // 结束判断
if y == 3 then // 当前 Y=3?
GETBIT(vpm, bv, 2) // 取位 2(Y3)→ bv
end if // 结束判断
if y == 4 then // 当前 Y=4?
GETBIT(vpm, bv, 3) // 取位 3(Y4)→ bv
end if // 结束判断
if y == 5 then // 当前 Y=5?
GETBIT(vpm, bv, 4) // 取位 4(Y5)→ bv
end if // 结束判断
if y == 6 then // 当前 Y=6?
GETBIT(vpm, bv, 5) // 取位 5(Y6)→ bv
end if // 结束判断
if y == 7 then // 当前 Y=7?
GETBIT(vpm, bv, 6) // 取位 6(Y7)→ bv
end if // 结束判断
if bv == 1 then // 该页面有内容?
SetData(x, "Local HMI", LW, 0, 1) // X=4 → LW-0
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-y1`**(Y1 初始状态 · 权限 A/B/C/D)
```
macro_command main() // 宏入口:按下 Y1 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 0 // 运行时读回的当前 X(1~4)
short y = 1 // 本按钮固定切到 Y=1
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // 当前 X 段页面存在位图
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bC = 0 // 类别 C 位(上料)
short bD = 0 // 类别 D 位(制丸)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bC, 2) // 取 bit2 → bC(C 上料)
GETBIT(cls, bD, 3) // 取 bit3 → bD(D 制丸)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if bC == 1 then // 含类别 C?
ok = 1 // 权限通过
end if // 结束判断
if bD == 1 then // 含类别 D?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 查当前 X 段位图
GetData(x, "Local HMI", LW, 0, 1) // 读当前 X → x
if x == 1 then // 当前在 X1 段?
GetData(vpm, "Local HMI", LW, 70, 1) // 读 X1 段位图 LW-70
end if // 结束判断
if x == 2 then // 当前在 X2 段?
GetData(vpm, "Local HMI", LW, 71, 1) // 读 X2 段位图 LW-71
end if // 结束判断
if x == 3 then // 当前在 X3 段?
GetData(vpm, "Local HMI", LW, 72, 1) // 读 X3 段位图 LW-72
end if // 结束判断
if x == 4 then // 当前在 X4 段?
GetData(vpm, "Local HMI", LW, 73, 1) // 读 X4 段位图 LW-73
end if // 结束判断
GETBIT(vpm, bv, 0) // 取位 0(Y1)→ bv
if bv == 1 then // 该页面有内容?
SetData(y, "Local HMI", LW, 1, 1) // Y=1 → LW-1
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-y2`**(Y2 运行 · 权限 A/B/C/D)
```
macro_command main() // 宏入口:按下 Y2 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 0 // 运行时读回的当前 X(1~4)
short y = 2 // 本按钮固定切到 Y=2
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // 当前 X 段页面存在位图
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bC = 0 // 类别 C 位(上料)
short bD = 0 // 类别 D 位(制丸)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bC, 2) // 取 bit2 → bC(C 上料)
GETBIT(cls, bD, 3) // 取 bit3 → bD(D 制丸)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if bC == 1 then // 含类别 C?
ok = 1 // 权限通过
end if // 结束判断
if bD == 1 then // 含类别 D?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 查当前 X 段位图
GetData(x, "Local HMI", LW, 0, 1) // 读当前 X → x
if x == 1 then // 当前在 X1 段?
GetData(vpm, "Local HMI", LW, 70, 1) // 读 X1 段位图 LW-70
end if // 结束判断
if x == 2 then // 当前在 X2 段?
GetData(vpm, "Local HMI", LW, 71, 1) // 读 X2 段位图 LW-71
end if // 结束判断
if x == 3 then // 当前在 X3 段?
GetData(vpm, "Local HMI", LW, 72, 1) // 读 X3 段位图 LW-72
end if // 结束判断
if x == 4 then // 当前在 X4 段?
GetData(vpm, "Local HMI", LW, 73, 1) // 读 X4 段位图 LW-73
end if // 结束判断
GETBIT(vpm, bv, 1) // 取位 1(Y2)→ bv
if bv == 1 then // 该页面有内容?
SetData(y, "Local HMI", LW, 1, 1) // Y=2 → LW-1
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-y3`**(Y3 配方 · 权限 A/B/C/D)
```
macro_command main() // 宏入口:按下 Y3 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 0 // 运行时读回的当前 X(1~4)
short y = 3 // 本按钮固定切到 Y=3
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // 当前 X 段页面存在位图
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bC = 0 // 类别 C 位(上料)
short bD = 0 // 类别 D 位(制丸)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bC, 2) // 取 bit2 → bC(C 上料)
GETBIT(cls, bD, 3) // 取 bit3 → bD(D 制丸)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if bC == 1 then // 含类别 C?
ok = 1 // 权限通过
end if // 结束判断
if bD == 1 then // 含类别 D?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 查当前 X 段位图
GetData(x, "Local HMI", LW, 0, 1) // 读当前 X → x
if x == 1 then // 当前在 X1 段?
GetData(vpm, "Local HMI", LW, 70, 1) // 读 X1 段位图 LW-70
end if // 结束判断
if x == 2 then // 当前在 X2 段?
GetData(vpm, "Local HMI", LW, 71, 1) // 读 X2 段位图 LW-71
end if // 结束判断
if x == 3 then // 当前在 X3 段?
GetData(vpm, "Local HMI", LW, 72, 1) // 读 X3 段位图 LW-72
end if // 结束判断
if x == 4 then // 当前在 X4 段?
GetData(vpm, "Local HMI", LW, 73, 1) // 读 X4 段位图 LW-73
end if // 结束判断
GETBIT(vpm, bv, 2) // 取位 2(Y3)→ bv
if bv == 1 then // 该页面有内容?
SetData(y, "Local HMI", LW, 1, 1) // Y=3 → LW-1
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-y4`**(Y4 设备参数 · 权限仅 A/B)
```
macro_command main() // 宏入口:按下 Y4 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 0 // 运行时读回的当前 X(1~4)
short y = 4 // 本按钮固定切到 Y=4
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // 当前 X 段页面存在位图
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 查当前 X 段位图
GetData(x, "Local HMI", LW, 0, 1) // 读当前 X → x
if x == 1 then // 当前在 X1 段?
GetData(vpm, "Local HMI", LW, 70, 1) // 读 X1 段位图 LW-70
end if // 结束判断
if x == 2 then // 当前在 X2 段?
GetData(vpm, "Local HMI", LW, 71, 1) // 读 X2 段位图 LW-71
end if // 结束判断
if x == 3 then // 当前在 X3 段?
GetData(vpm, "Local HMI", LW, 72, 1) // 读 X3 段位图 LW-72
end if // 结束判断
if x == 4 then // 当前在 X4 段?
GetData(vpm, "Local HMI", LW, 73, 1) // 读 X4 段位图 LW-73
end if // 结束判断
GETBIT(vpm, bv, 3) // 取位 3(Y4)→ bv
if bv == 1 then // 该页面有内容?
SetData(y, "Local HMI", LW, 1, 1) // Y=4 → LW-1
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-y5`**(Y5 I/O 监控 · 权限仅 A/B)
```
macro_command main() // 宏入口:按下 Y5 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 0 // 运行时读回的当前 X(1~4)
short y = 5 // 本按钮固定切到 Y=5
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // 当前 X 段页面存在位图
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 查当前 X 段位图
GetData(x, "Local HMI", LW, 0, 1) // 读当前 X → x
if x == 1 then // 当前在 X1 段?
GetData(vpm, "Local HMI", LW, 70, 1) // 读 X1 段位图 LW-70
end if // 结束判断
if x == 2 then // 当前在 X2 段?
GetData(vpm, "Local HMI", LW, 71, 1) // 读 X2 段位图 LW-71
end if // 结束判断
if x == 3 then // 当前在 X3 段?
GetData(vpm, "Local HMI", LW, 72, 1) // 读 X3 段位图 LW-72
end if // 结束判断
if x == 4 then // 当前在 X4 段?
GetData(vpm, "Local HMI", LW, 73, 1) // 读 X4 段位图 LW-73
end if // 结束判断
GETBIT(vpm, bv, 4) // 取位 4(Y5)→ bv
if bv == 1 then // 该页面有内容?
SetData(y, "Local HMI", LW, 1, 1) // Y=5 → LW-1
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-y6`**(Y6 报警 · 权限 A/B/C/D)
```
macro_command main() // 宏入口:按下 Y6 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 0 // 运行时读回的当前 X(1~4)
short y = 6 // 本按钮固定切到 Y=6
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // 当前 X 段页面存在位图
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bC = 0 // 类别 C 位(上料)
short bD = 0 // 类别 D 位(制丸)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bC, 2) // 取 bit2 → bC(C 上料)
GETBIT(cls, bD, 3) // 取 bit3 → bD(D 制丸)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if bC == 1 then // 含类别 C?
ok = 1 // 权限通过
end if // 结束判断
if bD == 1 then // 含类别 D?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 查当前 X 段位图
GetData(x, "Local HMI", LW, 0, 1) // 读当前 X → x
if x == 1 then // 当前在 X1 段?
GetData(vpm, "Local HMI", LW, 70, 1) // 读 X1 段位图 LW-70
end if // 结束判断
if x == 2 then // 当前在 X2 段?
GetData(vpm, "Local HMI", LW, 71, 1) // 读 X2 段位图 LW-71
end if // 结束判断
if x == 3 then // 当前在 X3 段?
GetData(vpm, "Local HMI", LW, 72, 1) // 读 X3 段位图 LW-72
end if // 结束判断
if x == 4 then // 当前在 X4 段?
GetData(vpm, "Local HMI", LW, 73, 1) // 读 X4 段位图 LW-73
end if // 结束判断
GETBIT(vpm, bv, 5) // 取位 5(Y6)→ bv
if bv == 1 then // 该页面有内容?
SetData(y, "Local HMI", LW, 1, 1) // Y=6 → LW-1
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-y7`**(Y7 数据趋势 · 权限 A/B/C/D)
```
macro_command main() // 宏入口:按下 Y7 按钮时执行
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 0 // 运行时读回的当前 X(1~4)
short y = 7 // 本按钮固定切到 Y=7
short win = 0 // 计算出的目标窗口号
short ok = 0 // 权限通过标志:1=放行
short bv = 0 // 页面存在标志:1=有内容
short vpm = 0 // 当前 X 段页面存在位图
short pop = 1 // 弹窗置位常量 1
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bC = 0 // 类别 C 位(上料)
short bD = 0 // 类别 D 位(制丸)
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bC, 2) // 取 bit2 → bC(C 上料)
GETBIT(cls, bD, 3) // 取 bit3 → bD(D 制丸)
if bA == 1 then // 含类别 A?
ok = 1 // 权限通过
end if // 结束判断
if bB == 1 then // 含类别 B?
ok = 1 // 权限通过
end if // 结束判断
if bC == 1 then // 含类别 C?
ok = 1 // 权限通过
end if // 结束判断
if bD == 1 then // 含类别 D?
ok = 1 // 权限通过
end if // 结束判断
if ok == 1 then // 权限通过 → 查当前 X 段位图
GetData(x, "Local HMI", LW, 0, 1) // 读当前 X → x
if x == 1 then // 当前在 X1 段?
GetData(vpm, "Local HMI", LW, 70, 1) // 读 X1 段位图 LW-70
end if // 结束判断
if x == 2 then // 当前在 X2 段?
GetData(vpm, "Local HMI", LW, 71, 1) // 读 X2 段位图 LW-71
end if // 结束判断
if x == 3 then // 当前在 X3 段?
GetData(vpm, "Local HMI", LW, 72, 1) // 读 X3 段位图 LW-72
end if // 结束判断
if x == 4 then // 当前在 X4 段?
GetData(vpm, "Local HMI", LW, 73, 1) // 读 X4 段位图 LW-73
end if // 结束判断
GETBIT(vpm, bv, 6) // 取位 6(Y7)→ bv
if bv == 1 then // 该页面有内容?
SetData(y, "Local HMI", LW, 1, 1) // Y=7 → LW-1
win = 101 + (x - 1) * 7 + (y - 1) // 算窗口号:101+(X-1)*7+(Y-1)
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
else // 该页面无内容
SetData(pop, "Local HMI", LB, 124, 1) // 置 LB-124 → 弹 16 号窗
end if // 结束判断
else // 权限不通过
SetData(pop, "Local HMI", LB, 110, 1) // 置 LB-110 → 弹 11 号无权限窗
end if // 结束判断
end macro_command // 宏结束
```
**`btn-login-index`**(登录:索引登入 → 按组定位;结果提示已内联,无宏编号依赖)
```
macro_command main() // 宏入口:点登录按钮时执行
short cmd = 2 // 命令=2:使用索引登入(读 LW-102 选中的账号)
short res = 0 // 存放命令结果(读 LW-101)
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 1 // 登录后入口 X 初值 = 1
short y = 1 // 登录后入口 Y = 1
short win = 0 // 计算出的目标窗口号
short idx = 7 // 提示编号(默认 7=登录失败)
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bC = 0 // 类别 C 位(上料)
short bD = 0 // 类别 D 位(制丸)
short z = 0 // 常量 0(清命令/清旧结果用)
SetData(z, "Local HMI", LW, 101, 1) // 先清旧结果 → 防止读到上一次的码
SetData(z, "Local HMI", LW, 261, 1) // 清底部提示 → 不显示上一次的信息
SetData(z, "Local HMI", LW, 100, 1) // 命令先清 0(保证 0→2 有跳变)
SetData(cmd, "Local HMI", LW, 100, 1) // 发命令 2 → LW-100(索引登入)
DELAY(300) // 等 0.3 秒
GetData(res, "Local HMI", LW, 101, 1) // 读命令结果 → res(1=成功)
if res == 0 then // 结果仍为 0?
DELAY(300) // 再等 0.3 秒
GetData(res, "Local HMI", LW, 101, 1) // 再读一次
end if // 结束判断
if res == 1 then // 结果=1?
idx = 1 // 提示编号 1:登录成功
end if // 结束判断
if res == 8 then // 结果=8?
idx = 2 // 提示编号 2:账号不存在
end if // 结束判断
if res == 16 then // 结果=16?
idx = 3 // 提示编号 3:密码错误
end if // 结束判断
if res == 32 then // 结果=32?
idx = 4 // 提示编号 4:命令无法执行
end if // 结束判断
if res == 64 then // 结果=64?
idx = 5 // 提示编号 5:名称不合法
end if // 结束判断
if res == 128 then // 结果=128?
idx = 6 // 提示编号 6:密码含无效字符
end if // 结束判断
if res == 0 then // 结果=0?
idx = 0 // 提示编号 0:不显示
end if // 结束判断
SetData(idx, "Local HMI", LW, 261, 1) // 提示编号 → LW-261(立即显示)
if res == 1 then // 登录成功?
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA(A 工程师)
GETBIT(cls, bB, 1) // 取 bit1 → bB(B 管理员)
GETBIT(cls, bC, 2) // 取 bit2 → bC(C 上料)
GETBIT(cls, bD, 3) // 取 bit3 → bD(D 制丸)
if bD == 1 then // 含类别 D(制丸)?
x = 3 // 只有制丸组 → 入口 X3
end if // 结束判断
if bA == 1 then // 含类别 A?
x = 1 // 入口 X1
end if // 结束判断
if bB == 1 then // 含类别 B?
x = 1 // 入口 X1
end if // 结束判断
if bC == 1 then // 含类别 C?
x = 1 // 入口 X1
end if // 结束判断
win = 101 + (x - 1) * 7 + (y - 1) // 算目标窗口号:101+(X-1)*7+(Y-1)
SetData(x, "Local HMI", LW, 0, 1) // X → LW-0
SetData(y, "Local HMI", LW, 1, 1) // Y → LW-1
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
end if // 结束判断
end macro_command // 宏结束
```
**`logout`**(注销并回登录页;10 号窗「打开窗口时执行」也用它)
```
macro_command main() // 宏入口:点注销按钮 / 进 10 号窗时执行
short cmd = 3 // 命令=3:注销当前账号
short win = 10 // 目标窗口号 = 10(登录页)
short z = 0 // 常量 0
short z8[8] = {0,0,0,0,0,0,0,0} // 8 个 0(清用户名/密码框用)
SetData(cmd, "Local HMI", LW, 100, 1) // 发命令 3 → LW-100(注销)
SetData(z, "Local HMI", LW, 0, 1) // X 清 0
SetData(z, "Local HMI", LW, 1, 1) // Y 清 0
SetData(z8[0], "Local HMI", LW, 104, 8) // 清用户名框 LW-104~111(下次默认下拉登入)
SetData(z8[0], "Local HMI", LW, 112, 8) // 清密码框 LW-112~119
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 10 → LW-2(切回登录页)
end macro_command // 宏结束
```
**`admin-open`**(登录页 logo 上透明按钮,长按 3 秒)
```
macro_command main() // 宏入口:长按登录页隐藏按钮时执行
short on = 1 // 置位常量 1
short z8[8] = {0,0,0,0,0,0,0,0} // 8 个 0(先清输入框)
SetData(z8[0], "Local HMI", LW, 104, 8) // 清用户名框 LW-104~111
SetData(z8[0], "Local HMI", LW, 112, 8) // 清密码框 LW-112~119
SetData(on, "Local HMI", LB, 125, 1) // 置 LB-125 → 弹 17 号管理员登录窗
end macro_command // 宏结束
```
**`admin-login`**(17 号窗「登录」:固定名称登入)
```
macro_command main() // 宏入口:点 17 号窗「登录」时执行
short cmd = 1 // 命令=1:使用名称登入(读 LW-104 + LW-112)
short res = 0 // 命令结果(读 LW-101)
short cls = 0 // 当前用户类别位(读 LW-9222)
short x = 1 // 入口 X 初值 = 1
short y = 1 // 入口 Y = 1
short win = 0 // 计算出的目标窗口号
short idx = 7 // 提示编号(默认 7=登录失败)
short bA = 0 // 类别 A 位(工程师)
short bB = 0 // 类别 B 位(管理员)
short bC = 0 // 类别 C 位(上料)
short bD = 0 // 类别 D 位(制丸)
short z = 0 // 常量 0
SetData(z, "Local HMI", LW, 101, 1) // 先清旧结果 → 防止读到上一次的码
SetData(z, "Local HMI", LW, 261, 1) // 清旧提示
SetData(z, "Local HMI", LW, 100, 1) // 命令先清 0
SetData(cmd, "Local HMI", LW, 100, 1) // 发命令 1 → LW-100(名称登入)
DELAY(300) // 等 0.3 秒
GetData(res, "Local HMI", LW, 101, 1) // 读命令结果 → res(1=成功)
if res == 0 then // 结果仍为 0?
DELAY(300) // 再等 0.3 秒
GetData(res, "Local HMI", LW, 101, 1) // 再读一次
end if // 结束判断
if res == 1 then // 结果=1?
idx = 1 // 提示编号 1:登录成功
end if // 结束判断
if res == 8 then // 结果=8?
idx = 2 // 提示编号 2:账号不存在
end if // 结束判断
if res == 16 then // 结果=16?
idx = 3 // 提示编号 3:密码错误
end if // 结束判断
if res == 32 then // 结果=32?
idx = 4 // 提示编号 4:命令无法执行
end if // 结束判断
if res == 64 then // 结果=64?
idx = 5 // 提示编号 5:名称不合法
end if // 结束判断
if res == 128 then // 结果=128?
idx = 6 // 提示编号 6:密码含无效字符
end if // 结束判断
if res == 0 then // 结果=0?
idx = 0 // 提示编号 0:不显示
end if // 结束判断
SetData(idx, "Local HMI", LW, 261, 1) // 提示编号 → LW-261(立即显示)
if res == 1 then // 登录成功?
SetData(z, "Local HMI", LB, 125, 1) // 清 LB-125 → 关 17 号弹窗
GetData(cls, "Local HMI", LW, 9222, 1) // 读当前用户类别位 → cls
GETBIT(cls, bA, 0) // 取 bit0 → bA
GETBIT(cls, bB, 1) // 取 bit1 → bB
GETBIT(cls, bC, 2) // 取 bit2 → bC
GETBIT(cls, bD, 3) // 取 bit3 → bD
if bD == 1 then // 含类别 D?
x = 3 // 只有制丸组 → X3
end if // 结束判断
if bA == 1 then // 含类别 A?
x = 1 // 入口 X1
end if // 结束判断
if bB == 1 then // 含类别 B?
x = 1 // 入口 X1
end if // 结束判断
if bC == 1 then // 含类别 C?
x = 1 // 入口 X1
end if // 结束判断
win = 101 + (x - 1) * 7 + (y - 1) // 算目标窗口号
SetData(x, "Local HMI", LW, 0, 1) // X → LW-0
SetData(y, "Local HMI", LW, 1, 1) // Y → LW-1
SetData(win, "Local HMI", LW, 2, 1) // 窗口号 → LW-2(触发切窗)
end if // 结束判断
end macro_command // 宏结束
```
**`admin-close`**(17 号窗「取消」)
```
macro_command main() // 宏入口:点 17 号窗「取消」时执行
short z = 0 // 常量 0
short z8[8] = {0,0,0,0,0,0,0,0} // 8 个 0
SetData(z, "Local HMI", LB, 125, 1) // 清 LB-125 → 关 17 号窗
SetData(z8[0], "Local HMI", LW, 104, 8) // 清用户名框
SetData(z8[0], "Local HMI", LW, 112, 8) // 清密码框
end macro_command // 宏结束
```
**`close-msg`**(关闭无权限提示窗)
```
macro_command main() // 宏入口:点 11 号窗「确定」时执行
short z = 0 // 常量 0
SetData(z, "Local HMI", LB, 110, 1) // 清 LB-110 → 关闭 11 号无权限窗
end macro_command // 宏结束
```
**`close-nopage`**(关闭 16 号「无内容」提示窗)
```
macro_command main() // 宏入口:点 16 号窗「确定」时执行
short z = 0 // 常量 0
SetData(z, "Local HMI", LB, 124, 1) // 清 LB-124 → 关闭 16 号无内容窗
end macro_command // 宏结束
```
**用户管理 `usr-*`**
| 宏 | 命令 | 说明 |
| --- | --- | --- |
| `usr-init` | — | 14 号窗「打开窗口时执行」:清 `LW-104`/`LW-112`/`LW-103`/`LW-101`,清 `LB-121` |
| `user-open` | — | 顶部按钮:仅 B/admin → 置 `LB-122` |
| `usr-back` | — | 清 `LB-122` |
| `usr-add` | `5` | 新增(`LW-104`+`LW-112`+`LW-103`) |
| `usr-delete` | — | 置 `LB-121` 弹确认 |
| `usr-delete-ok` | `8` | 按索引删除 |
| `usr-delete-cancel` | — | 清 `LB-121` |
| `usr-getlevel` | `14` | 按索引读权限 → `LW-103` |
| `usr-setlevel` | `10` | 按索引设权限 |
| `usr-setpwd` | `12` | 按索引设密码 |
```
macro_command main() // 宏入口:用户管理按钮(以 cmd=14 读取权限为例)
short cmd = 14 // 命令值:改成 5/8/10/12 等即为对应功能
SetData(cmd, "Local HMI", LW, 100, 1) // 发命令 → LW-100
end macro_command // 宏结束
```
> 其余 `usr-*` 同上模板:`cmd` = 5 / 8 / 10 / 12;`user-open` 置 / `usr-back` 清 `LB-122`,`usr-delete` / `usr-delete-cancel` 置 / 清 `LB-121`,`usr-init` 清输入。
**关于窗 `about-*`**:`about-open` 置 `LB-123`(弹 13 号窗);`about-close` 清 `LB-123`。
**修改时间**
| 宏 | 触发 | 作用 |
| --- | --- | --- |
| `open-time` | 时钟上透明按钮(仅 B) | 读 `LW-9017`~`9022` → `LW-40`~`45`,置 `LB-120` |
| `set-time` | 12 号窗「设定」 | `LW-40`~`45` → `LW-9017`~`9022`(设置 RTC),清 `LB-120` |
| `close-time` | 12 号窗「取消」 | 清 `LB-120` |
```
macro_command main() // 宏入口:改时间弹窗点「设定」时执行
short v[6] = {0,0,0,0,0,0} // 暂存数组:秒/分/时/日/月/年
short z = 0 // 常量 0
GetData(v[0], "Local HMI", LW, 40, 6) // 从 LW-40~45 读入 6 个值 → v
SetData(v[0], "Local HMI", LW, 9017, 6) // v 写入 RTC 寄存器 LW-9017~9022(设置时间)
SetData(z, "Local HMI", LB, 120, 1) // 清 LB-120 → 关闭 12 号弹窗
end macro_command // 宏结束
```
**网络设置 `net-*`**
**`net-read`**(13 号窗「打开窗口时执行」:系统值 → 暂存 RW)
```
macro_command main() // 宏入口:进 13 号窗时执行
short v[4] = {0,0,0,0} // 4 字暂存数组
short line = 1 // 制丸线别(1=A / 2=B)
GetData(line, "Local HMI", RW, 61, 1) // 读 RW-61 线别
GetData(v[0], "Local HMI", LW, 9129, 4) // 读 HMI IP
SetData(v[0], "Local HMI", RW, 20, 4) // → RW-20~23
GetData(v[0], "Local HMI", LW, 10750, 4) // 读 HMI 掩码
SetData(v[0], "Local HMI", RW, 24, 4) // → RW-24~27
GetData(v[0], "Local HMI", LW, 9125, 4) // 读 HMI 网关
SetData(v[0], "Local HMI", RW, 28, 4) // → RW-28~31
GetData(v[0], "Local HMI", LW, 9600, 4) // 读上料 PLC(设备4)IP
SetData(v[0], "Local HMI", RW, 40, 4) // → RW-40~43
GetData(v[0], "Local HMI", LW, 9605, 4) // 读制丸 PLC(设备5)IP
if line == 1 then // 当前选 A 线?
SetData(v[0], "Local HMI", RW, 44, 4) // → RW-44~47(制丸A)
else // 当前选 B 线
SetData(v[0], "Local HMI", RW, 48, 4) // → RW-48~51(制丸B)
end if // 结束判断
end macro_command // 宏结束
```
**`net-apply`**(工程宏 ID 037;13 号窗「应用」按钮 + 宏属性勾「当 HMI 启动时即执行一次」)
> **设备归属(10-27 按 EB 设备列表实测,数字以此为准)**
> `设备4 = 制丸1(192.168.189.22)`、`设备5 = 上料清洗(192.168.189.2)`,两台都是 S7CommPlus + 符号寻址。
> 所以:**上料 IP → `LW-9605` / `LB-10071`(设备5)**,**制丸 IP → `LW-9600` / `LB-10070`(设备4)**。
```
macro_command main() // 宏入口:点「应用」/ 开机自动套用
short v[4] = {0,0,0,0} // 4 字暂存数组
short hmi0 = 0 // HMI IP 第一段(判断是否配置过)
short role = 0 // 本机角色(1上料/2制丸A/3制丸B)
short line = 1 // 制丸线别(1=A/2=B)
short okp = 0 // 是否连接制丸设备:1=连
short on = 1 // 置位常量
short z = 0 // 常量 0
GetData(hmi0, "Local HMI", RW, 20, 1) // 读 RW-20(HMI IP 第一段)
GetData(role, "Local HMI", RW, 60, 1) // 读 RW-60(本机角色)
GetData(line, "Local HMI", RW, 61, 1) // 读 RW-61(线别)
if line == 0 then // 线别未设置?
line = 1 // 默认 A 线
end if // 结束判断
if role == 1 then // 上料屏?
okp = 1 // 连制丸设备(线别按 RW-61)
end if // 结束判断
if role == 2 then // 制丸A屏?
line = 1 // 强制 A 线
okp = 1 // 连制丸设备
end if // 结束判断
if role == 3 then // 制丸B屏?
line = 2 // 强制 B 线
okp = 1 // 连制丸设备
end if // 结束判断
SetData(line, "Local HMI", RW, 61, 1) // 回写线别(界面显示一致)
if hmi0 == 0 then // HMI IP 没填 → 跳过 HMI 部分
hmi0 = 0 // (保持原 HMI 网络)
else // 已填 → 应用 HMI 网络
GetData(v[0], "Local HMI", RW, 20, 4) // RW → HMI IP
SetData(v[0], "Local HMI", LW, 9129, 4) // 写 LW-9129~9132
GetData(v[0], "Local HMI", RW, 24, 4) // RW → HMI 掩码
SetData(v[0], "Local HMI", LW, 10750, 4) // 写 LW-10750~10753
GetData(v[0], "Local HMI", RW, 28, 4) // RW → HMI 网关
SetData(v[0], "Local HMI", LW, 9125, 4) // 写 LW-9125~9128
SetData(on, "Local HMI", LB, 12094, 1) // 置 LB-12094 → HMI 网络生效
end if // 结束判断
GetData(v[0], "Local HMI", RW, 40, 4) // RW → 上料 PLC IP
if v[0] == 0 then // 没填(新屏/模拟)→ 不写、不重连
v[0] = 0 // 保留工程里的设备 IP
else // 已填 → 套用(设备5 = 上料清洗)
SetData(v[0], "Local HMI", LW, 9605, 4) // 写设备5 IP
SetData(on, "Local HMI", LB, 10071, 1) // 重连设备5
end if // 结束判断
if okp == 1 then // 需要连制丸设备?
if line == 1 then // 选 A 线
GetData(v[0], "Local HMI", RW, 44, 4) // RW → 制丸A IP
else // 选 B 线
GetData(v[0], "Local HMI", RW, 48, 4) // RW → 制丸B IP
end if // 结束判断
if v[0] == 0 then // 没填 → 不写、不重连
v[0] = 0 // 保留工程里的设备 IP
else // 已填 → 套用(设备4 = 制丸1)
SetData(v[0], "Local HMI", LW, 9600, 4) // 写设备4 IP
SetData(on, "Local HMI", LB, 10070, 1) // 重连设备4
end if // 结束判断
end if // 结束判断(角色=0:不连制丸设备,防误连)
DELAY(1000) // 等 1 秒(嫌开机慢可改 300)
SetData(z, "Local HMI", LB, 12094, 1) // 清 LB-12094
SetData(z, "Local HMI", LB, 10070, 1) // 清 LB-10070
SetData(z, "Local HMI", LB, 10071, 1) // 清 LB-10071
end macro_command // 宏结束
```
**与工程现版(10-27 摘录)的三个差别**
| # | 现版 | 本节 |
| --- | --- | --- |
| 1 | 注释把设备号写反(`写上料 PLC(设备4)`) | 注释已改正;**数字一个没改** |
| 2 | 无 `v[0]==0` 保护,RW 为空时把 IP 刷成 `0.0.0.0` | 首段为 0 跳过写入与重连 |
| 3 | `DELAY(1000)` | 保留,可改 300 缩短开机等待 |
> `LB-11963`/`LB-11964` 那条屏蔽设备 1~8 通讯弹窗的宏(ID 048 `屏蔽通讯异常提示`,周期执行)与本宏无关,别混。
**`line-ab-switch`**(13 号窗「A/B 切换」按钮;仅本机角色=1 生效)
```
macro_command main() // 宏入口:点 A/B 线切换按钮
short v[4] = {0,0,0,0} // 4 字暂存数组
short role = 0 // 本机角色(读 RW-60)
short line = 1 // 当前线别
short on = 1 // 置位常量
short z = 0 // 常量 0
GetData(role, "Local HMI", RW, 60, 1) // 读本机角色
if role == 1 then // 只有上料屏允许切换
GetData(line, "Local HMI", RW, 61, 1) // 读当前线别
if line == 1 then // 当前 A → 切 B
line = 2 // 目标 B
else // 当前 B → 切 A
line = 1 // 目标 A
end if // 结束判断
SetData(line, "Local HMI", RW, 61, 1) // 写回 RW-61
if line == 1 then // 目标 A 线
GetData(v[0], "Local HMI", RW, 44, 4) // 取制丸A IP
else // 目标 B 线
GetData(v[0], "Local HMI", RW, 48, 4) // 取制丸B IP
end if // 结束判断
SetData(v[0], "Local HMI", LW, 9605, 4) // 写设备5 IP
SetData(on, "Local HMI", LB, 10071, 1) // 重连设备5
DELAY(1000) // 等 1 秒
SetData(z, "Local HMI", LB, 10071, 1) // 清重连位
end if // 非上料屏:无动作(线别锁定)
end macro_command // 宏结束
```
### X2Y2 分区聚焦弹窗(工程实际名 `x2y2-focus-area*`)
> 施工见 `开发主文件.md` 7.7.3。**旧文档的 `area-1~4` / `area-close` 作废**,工程实际是:
| 宏 | 触发 | 作用 |
| --- | --- | --- |
| `x2y2-focus-area1` | 区域①透明键 | 写 `LW-50` = 目标窗口号 |
| `x2y2-focus-area2` | 区域②透明键 | 同上 |
| `x2y2-focus-area3` | 区域③透明键 | 同上 |
| `x2y2-focus-area-close` | 「关闭」键 / X2Y2 打开窗口时 | `LW-50` = 0 收起 |
**只有 3 个区域**(原第④区已并入③),没有 area-4。
**窗口号已确认**:工程窗口表里 `30/31/32 = x2y2-focus-area1/2/3`,所以 `LW-50` 写的是 **30/31/32**;旧版本节写的 `141/142/143` 作废(`地址表.md` 5.1 已同步)。