主题
块运算与字符串(FNC 190-219)
这一段是 FX3U 里比较少用但很实用的部分:块运算让您对一整片 D 寄存器做加减和比较,字符串指令让 PLC 能直接拼接、截取、查找 ASCII 字符串(做报文、做屏幕显示时很省事)。
数据块运算(FNC 192-199)
块运算的对象是「从 S 开始的连续 n 个字」。全部只支持 16 位,全部支持 P。
| FNC | 助记符 | 操作数 | 功能 |
|---|---|---|---|
| 192 | BK+ | S1 S2 D n | 块加法 |
| 193 | BK- | S1 S2 D n | 块减法 |
| 194 | BKCMP= | S1 S2 D n | 块比较 等于 |
| 195 | BKCMP> | S1 S2 D n | 块比较 大于 |
| 196 | BKCMP< | S1 S2 D n | 块比较 小于 |
| 197 | BKCMP<> | S1 S2 D n | 块比较 不等于 |
| 198 | BKCMP<= | S1 S2 D n | 块比较 小于等于 |
| 199 | BKCMP>= | S1 S2 D n | 块比较 大于等于 |
BK+ D0 D100 D200 K10 ; D0~D9 + D100~D109 → D200~D209
BKCMP> D0 D100 M0 K10 ; 逐个比较,结果写到 M0~M9块比较的结果是每个字一个位:第 i 个字满足条件则 D+i 位置的位为 ON。10 个字比较就占 10 个 M 点。
块比较适合做「一批数都合格吗」
把 10 路 AI 的上限放在 D100~D109,用 BKCMP<= D0 D100 M0 K10,然后 AND M0 AND M1 ... 或者用 WSUM 之类统计,比写 10 段独立比较清爽很多。
字符串指令(FNC 200-209)
字符串在 D 寄存器里按「每字 2 个 ASCII 字符、低字节在前」存放,以 \0 结尾。
| FNC | 助记符 | D | P | 操作数 | 功能 |
|---|---|---|---|---|---|
| 200 | STR | ✔ | ✔ | S1 S2 D | 数值→字符串(带格式) |
| 201 | VAL | ✔ | ✔ | S D1 D2 | 字符串→数值 |
| 202 | $+ | ✘ | ✔ | S1 S2 D | 字符串连接 |
| 203 | LEN | ✘ | ✔ | S D | 求字符串长度 |
| 204 | RIGHT | ✘ | ✔ | S D n | 从右取 n 个字符 |
| 205 | LEFT | ✘ | ✔ | S D n | 从左取 n 个字符 |
| 206 | MIDR | ✘ | ✔ | S D n | 从中间取子串 |
| 207 | MIDW | ✘ | ✔ | S1 D S2 | 替换中间的子串 |
| 208 | INSTR | ✘ | ✔ | S1 S2 D n | 查找子串位置 |
| 209 | $MOV | ✘ | ✔ | S D | 字符串传送 |
STR D0 D10 D20 ; 按 D0/D1 指定的格式把 D10 转成字符串放 D20
LEN D20 D30 ; 求长度 → D30
$+ D20 D40 D60 ; D20 和 D40 拼接 → D60
INSTR D20 D40 D50 K1 ; 在 D40 里从第 1 个字符开始找 D20 → 位置写 D50$+(字符串连接)与 $MOV(字符串传送)在右侧「指令」面板里可以直接搜到,但它们是参考条目、暂不支持拖入, 照上面的写法在指令表里直接输入即可。
字符串常量的写法:双引号直接写在指令里
现场最常见的需求是把 IP、设备名、密码这类字符串填进寄存器再发出去,直接写双引号就行:
LD M8000
$MOV "192.168.2.1" D300 ; 字符串常量 → D300 起- 双引号里就是原文,一个字符占一个字,末尾自动补终止字;上面这一条实测占 17 步(
$MOV操作码 + 13 个字符字 + 目的地址 +END),比想象中吃步数,别在容量紧的程序里成串地塞。 - 引号里的
;不算注释,可以放心写进字符串内容;注释仍然只能用;和//,写在引号外。 $+的三个操作数都是"存放字符串的起始地址",不是字符串本身。
两个字符串常量不要连着写
实测三种写法的结果(前两种可用,第三种不可用):
| 写法 | 结果 |
|---|---|
$+ "LP" D20 D100 | 可用 —— 只有一个字面量 |
$+ D20 D40 D60 | 可用 —— 全部用地址 |
$+ "LP" "PLC" D100 | 编不过,报 程序缺少 END 指令 |
前一种能用是因为字符串长度是跟着内容走的:两个字面量挨在一起时,前一个会把后一个的内容 一起吞进去,后面那条 END 就被当成字符串的一部分吃掉了,于是编译器说"程序缺少 END"。 要把两个字面量拼起来,先各用一条 $MOV 放进两个 D,再 $+ D… D… D…:
LD M8000
$MOV "LP" D20 ; 第一段放 D20 起
$MOV "PLC" D40 ; 第二段放 D40 起
$+ D20 D40 D100 ; 拼接结果放 D100 起
ENDSTR 的格式约定:S1 占 2 个字,S1=总位数、S1+1=小数位数。
- 16 位:总位数 2~8,小数位 0~5
- 32 位(DSTR):总位数 2~13,小数位 0~10
- 要求
小数位 + 3 ≤ 总位数,越界报 6581 / 6582
其他限制:
MIDR/MIDW的起始位置从 1 开始数(不是 0),越界分别报 6783 / 6784INSTR只有 16 位版,找不到时结果为 0- 字符串长度受目标 D 区大小限制,写之前留够连续寄存器
字符串指令最常用在拼 MODBUS/自由口报文
不过如果您要做的是复杂的字符串处理、JSON 拼装、HTTP 请求,用 Lua 会比梯形图轻松得多,见 Lua 能力总览。梯形图字符串指令适合简单固定的场景。
数据表操作(FNC 210-214)
| FNC | 助记符 | D | P | 操作数 | 功能 |
|---|---|---|---|---|---|
| 210 | FDEL | ✘ | ✔ | D S n | 从数据表删除一项 |
| 211 | FINS | ✘ | ✔ | S D n | 向数据表插入一项 |
| 212 | POP | ✘ | ✔ | S D n | 后入先出读出 |
| 213 | SFR | ✘ | ✔ | D n | 16 位数据右移 n 位(n=1~15),移出的最低位进 M8022 |
| 214 | SFL | ✘ | ✔ | D n | 16 位数据左移 n 位(n=1~15),移出的最高位进 M8022 |
FINS D0 D100 K3 ; 把 D0 插入到 D100 数据表的第 3 项
FDEL D0 D100 K3 ; 把第 3 项删掉,值取到 D0
POP D0 D10 K5 ; 配合 SFWR/SFRD 做后入先出FDEL / FINS 会自动搬移表内后续数据,但本机的表长那一格要自己维护 —— 这两条只挪数据, 不会替你把首格的个数加 1 或减 1,也不检查位置越界。三菱资料里说它会自动增减长度,本机不是。
各指令详细说明
数据块运算 BK+ / BKCMP… —— 8 条一起讲
这 8 条一次对一整片连续的 D 做同一种运算,4 则运算 2 条、比较 6 条。全部只有 16 位形态、 全部支持 P(脉冲执行),操作数都是 4 个:S1 S2 D n。
| 面板里的名字 | 指令表里要敲的 | 干什么 | 步数 | FNC |
|---|---|---|---|---|
BK_ADD | BK+ | D[i] = S1[i] + S2[i] | 9 | FNC 192 |
BK_SUB | BK- | D[i] = S1[i] - S2[i] | 9 | FNC 193 |
BK_AMOUNT | BKCMP= | 相等 → 位置 ON | 9 | FNC 194 |
BK_BIG | BKCMP> | 大于 → 位置 ON | 9 | FNC 195 |
BK_LESS | BKCMP< | 小于 → 位置 ON | 9 | FNC 196 |
BK_NOT_AMOUNT | BKCMP<> | 不相等 → 位置 ON | 9 | FNC 197 |
BK_LESS_AMOUNT | BKCMP<= | 小于等于 → 位置 ON | 9 | FNC 198 |
BK_BIG_AMOUNT | BKCMP>= | 大于等于 → 位置 ON | 9 | FNC 199 |
BK+ D0 D100 D200 K10 ; D0~D9 与 D100~D109 逐字相加 → D200~D209
BKCMP<= D0 D100 M0 K10 ; 逐字比较,10 个结果写成 M0~M9 这 10 个位三条必须知道的限制:
n不检查范围。填 0 或负数整条不执行;填太大就一路写到后面的软元件上,不报错。 写之前自己核对S1、S2、D三片区域加上n个字之后还在您预留的范围内,且互不重叠。- 加减没有进位/借位,逐字独立算,超过 16 位范围直接回绕(
32767 + 1 = -32768)。 要 32 位逐字运算请用DADD/DSUB分段写,别指望BK+帮您进位。 - 比较结果是按位排的:第
i个字满足条件,就把从D起的第i位置 ON。D给位软元件(M0)时占n个位;给字软元件时第i位落在D+i/16这个字的第i%16位上。 比较按有符号数算,-1 < 1。
手写指令表只认右列那串
左列那 8 个 BK_ADD 之类的名字是面板显示名,部分老版本上位机才这么显示。 把它们抄进指令表会被判未知指令 —— 一律照中间那一列敲。
$+ — 字符串连接
| 项目 | 说明 |
|---|---|
| 格式 | $+ S1(前串), S2(后串), D(结果首址) |
| 操作数 | S1, S2, D |
| 示例 | $+ D20 D40 D60 |
| 步数 | 5 |
| FNC | FNC 202 |
把 S2 接在 S1 后面,结果写到 D。字符串在 D 里的存法是每字 2 个字符、低字节在前,以 \0 结尾, 所以 D60 起始要留够 (长度+1)/2 个字。
- 从 D 区取串最长 1023 个字符;直接写双引号常量(
$+ "ABC" D40 D60)最长 32 个字符。 - 不检查目标放不放得下:拼起来超长会写穿到
D后面的寄存器上。拼接前先LEN一下两个源串, 或者干脆给D留一截富余区。 - 支持 P(脉冲执行)。注意这条在判断能流之前就把操作数读掉了,不通电时占的步数一样多。
$MOV — 字符串传送
| 项目 | 说明 |
|---|---|
| 格式 | $MOV S(源串), D(目标首址) |
| 操作数 | S, D |
| 示例 | $MOV D20 D60 |
| 步数 | 5 |
| FNC | FNC 209 |
整串复制,长度按源串的 \0 自动定,比按字数 BMOV 省事。长度限制与越界行为同 $+ (源串最长 1023 字符、常量最长 32 字符,目标超长不报错)。支持 P(脉冲执行)。
$MOV "OK" D60 ; 把两个字符连结束符写进 D60
$MOV D20 D60 ; D20 那串整串搬到 D60
LEN D60 D70 ; 顺便看看多长POP — 后入先出读出
| 项目 | 说明 |
|---|---|
| 格式 | POP S(表首址), D(取到的值放这), n(表容量) |
| 操作数 | S, D, n |
| 示例 | POP D0 D10 K5 |
| 步数 | 7 |
| FNC | FNC 212 |
和 SFWR(写入)配对的"最后写进去的最先取出来"。S 那一格存当前条数,数据从 S+1 起排, n 是这张表的容量。每执行一次取走最后一条、条数 -1。
表空了继续弹不报错
S 里的条数已经是 0 时再 POP,不会报错,取到的是 S+1 那一格的现值(也就是上一条留下的残值)。 所以用 POP 之前要么自己判条数(CMP D0 K0 M0 这类),要么配合 SFWR 的写入计数用。 这一点和 ZPOP(空栈报 6781)不一样,别记混。
没有 32 位形态。
DESTR — 浮点数→字符串。格式操作数占连续 3 个字(方式 / 总位数 / 小数位数)
| 项目 | 说明 |
|---|---|
| 格式 | DESTR 源 S(浮点), 格式 S2(3字), 目标 D |
| 操作数 | 源 S(浮点), 格式 S2(3字), 目标 D |
| 示例 | DESTR D10 D20 D100 |
| 步数 | 13 |
| FNC | FNC 116 |
DESTR D10 D20 D100DEVAL — 字符串→浮点数。只有 2 个操作数
| 项目 | 说明 |
|---|---|
| 格式 | DEVAL 源 S, 目标 D(浮点) |
| 操作数 | 源 S, 目标 D(浮点) |
| 示例 | DEVAL D100 D10 |
| 步数 | 9 |
| FNC | FNC 117 |
DEVAL D100 D10STR — 数值→字符串
| 项目 | 说明 |
|---|---|
| 格式 | STR S1(存"所有位数/小数位数"的软元件,占 D 与 D+1), S2(BIN 源), D(字符串目标) |
| 操作数 | S1(存"所有位数/小数位数"的软元件,占 D 与 D+1), S2(BIN 源), D(字符串目标) |
| 示例 | STR D0 D10 D20 |
| 步数 | 7 |
| FNC | FNC 200 |
STR D0 D10 D20DSTR — 32 位数值→字符串
| 项目 | 说明 |
|---|---|
| 格式 | DSTR S1(存位数的软元件), S2(BIN 源), D(字符串目标) |
| 操作数 | S1(存位数的软元件), S2(BIN 源), D(字符串目标) |
| 示例 | DSTR D0 D10 D20 |
| 步数 | 13 |
| FNC | FNC 200 (D) |
DSTR D0 D10 D20VAL — 字符串→数值(BIN)
| 项目 | 说明 |
|---|---|
| 格式 | VAL S(字符串), D1(存"位数"的软元件), D2(BIN 目标) |
| 操作数 | S(字符串), D1(存"位数"的软元件), D2(BIN 目标) |
| 示例 | VAL D0 D10 D20 |
| 步数 | 7 |
| FNC | FNC 201 |
VAL D0 D10 D20LEN — 求字符串长度
| 项目 | 说明 |
|---|---|
| 格式 | LEN 源 S, 目标 D |
| 操作数 | 源 S, 目标 D |
| 示例 | LEN D0 D10 |
| 步数 | 5 |
| FNC | FNC 203 |
LEN D0 D10LEFT — 从左侧取子串
| 项目 | 说明 |
|---|---|
| 格式 | LEFT 源 S, 长度 n, 目标 D |
| 操作数 | 源 S, 长度 n, 目标 D |
| 示例 | LEFT D0 K3 D10 |
| 步数 | 7 |
| FNC | FNC 205 |
LEFT D0 K3 D10RIGHT — 从右侧取子串
| 项目 | 说明 |
|---|---|
| 格式 | RIGHT 源 S, 长度 n, 目标 D |
| 操作数 | 源 S, 长度 n, 目标 D |
| 示例 | RIGHT D0 K3 D10 |
| 步数 | 7 |
| FNC | FNC 204 |
RIGHT D0 K3 D10MIDR — 从中间读取子串
| 项目 | 说明 |
|---|---|
| 格式 | MIDR 源 S, 起始 n, 目标 D |
| 操作数 | 源 S, 起始 n, 目标 D |
| 示例 | MIDR D0 K2 D10 |
| 步数 | 7 |
| FNC | FNC 206 |
MIDR D0 K2 D10MIDW — 从中间写入子串
| 项目 | 说明 |
|---|---|
| 格式 | MIDW 源 S, 起始 n, 目标 D |
| 操作数 | 源 S, 起始 n, 目标 D |
| 示例 | MIDW D0 K2 D10 |
| 步数 | 7 |
| FNC | FNC 207 |
MIDW D0 K2 D10INSTR — 字符串检索(在 S1 中查找 S2 的位置)
| 项目 | 说明 |
|---|---|
| 格式 | INSTR 源 S1, 检索 S2, 结果 D, 长度 n |
| 操作数 | 源 S1, 检索 S2, 结果 D, 长度 n |
| 示例 | INSTR D0 D10 D20 K4 |
| 步数 | 9 |
| FNC | FNC 208 |
INSTR D0 D10 D20 K4FDEL — 删除表中指定位置的数据(后续数据前移),被删掉的值送到第一个操作数
| 项目 | 说明 |
|---|---|
| 格式 | FDEL D(取出值), S(表首址), n(删除位置) |
| 操作数 | D(取出值), S(表首址), n(删除位置) |
| 示例 | FDEL D0 D10 K3 |
| 步数 | 7 |
| FNC | FNC 210 |
FDEL D0 D10 K3FINS — 向表中指定位置插入数据(后续数据后移)
| 项目 | 说明 |
|---|---|
| 格式 | FINS S(插入值), D(表首址), n(插入位置) |
| 操作数 | S(插入值), D(表首址), n(插入位置) |
| 示例 | FINS D0 D10 K3 |
| 步数 | 7 |
| FNC | FNC 211 |
FINS D0 D10 K3SFL — 字左移(带进位):D 的 16 位整体左移 n 位,移出的最高位进 M8022
| 项目 | 说明 |
|---|---|
| 格式 | SFL D(数据), n(移位数 1~15) |
| 操作数 | D(数据), n(移位数 1~15) |
| 示例 | SFL D0 K3 |
| 步数 | 5 |
| FNC | FNC 214 |
SFL D0 K3SFR — 字右移(带进位):D 的 16 位整体右移 n 位,移出的最低位进 M8022
| 项目 | 说明 |
|---|---|
| 格式 | SFR D(数据), n(移位数 1~15) |
| 操作数 | D(数据), n(移位数 1~15) |
| 示例 | SFR D0 K3 |
| 步数 | 5 |
| FNC | FNC 213 |
SFR D0 K3