Skip to content

块运算与字符串(FNC 190-219) ​

这一段是 FX3U 里比较少用但很实用的部分:块运算让您对一整片 D 寄存器做加减和比较,字符串指令让 PLC 能直接拼接、截取、查找 ASCII 字符串(做报文、做屏幕显示时很省事)。

数据块运算(FNC 192-199) ​

块运算的对象是「从 S 开始的连续 n 个字」。全部只支持 16 位,全部支持 P。

FNC助记符操作数功能
192BK+S1 S2 D n块加法
193BK-S1 S2 D n块减法
194BKCMP=S1 S2 D n块比较 等于
195BKCMP>S1 S2 D n块比较 大于
196BKCMP<S1 S2 D n块比较 小于
197BKCMP<>S1 S2 D n块比较 不等于
198BKCMP<=S1 S2 D n块比较 小于等于
199BKCMP>=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助记符DP操作数功能
200STR✔✔S1 S2 D数值→字符串(带格式)
201VAL✔✔S D1 D2字符串→数值
202$+✘✔S1 S2 D字符串连接
203LEN✘✔S D求字符串长度
204RIGHT✘✔S D n从右取 n 个字符
205LEFT✘✔S D n从左取 n 个字符
206MIDR✘✔S D n从中间取子串
207MIDW✘✔S1 D S2替换中间的子串
208INSTR✘✔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 起
END

STR 的格式约定:S1 占 2 个字,S1=总位数、S1+1=小数位数。

  • 16 位:总位数 2~8,小数位 0~5
  • 32 位(DSTR):总位数 2~13,小数位 0~10
  • 要求 小数位 + 3 ≤ 总位数,越界报 6581 / 6582

其他限制:

  • MIDR / MIDW 的起始位置从 1 开始数(不是 0),越界分别报 6783 / 6784
  • INSTR 只有 16 位版,找不到时结果为 0
  • 字符串长度受目标 D 区大小限制,写之前留够连续寄存器

字符串指令最常用在拼 MODBUS/自由口报文

不过如果您要做的是复杂的字符串处理、JSON 拼装、HTTP 请求,用 Lua 会比梯形图轻松得多,见 Lua 能力总览。梯形图字符串指令适合简单固定的场景。

数据表操作(FNC 210-214) ​

FNC助记符DP操作数功能
210FDEL✘✔D S n从数据表删除一项
211FINS✘✔S D n向数据表插入一项
212POP✘✔S D n后入先出读出
213SFR✘✔D n16 位数据右移 n 位(n=1~15),移出的最低位进 M8022
214SFL✘✔D n16 位数据左移 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_ADDBK+D[i] = S1[i] + S2[i]9FNC 192
BK_SUBBK-D[i] = S1[i] - S2[i]9FNC 193
BK_AMOUNTBKCMP=相等 → 位置 ON9FNC 194
BK_BIGBKCMP>大于 → 位置 ON9FNC 195
BK_LESSBKCMP<小于 → 位置 ON9FNC 196
BK_NOT_AMOUNTBKCMP<>不相等 → 位置 ON9FNC 197
BK_LESS_AMOUNTBKCMP<=小于等于 → 位置 ON9FNC 198
BK_BIG_AMOUNTBKCMP>=大于等于 → 位置 ON9FNC 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
FNCFNC 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
FNCFNC 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
FNCFNC 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
FNCFNC 116
DESTR D10 D20 D100

DEVAL — 字符串→浮点数。只有 2 个操作数 ​

项目说明
格式DEVAL 源 S, 目标 D(浮点)
操作数源 S, 目标 D(浮点)
示例DEVAL D100 D10
步数9
FNCFNC 117
DEVAL D100 D10

STR — 数值→字符串 ​

项目说明
格式STR S1(存"所有位数/小数位数"的软元件,占 D 与 D+1), S2(BIN 源), D(字符串目标)
操作数S1(存"所有位数/小数位数"的软元件,占 D 与 D+1), S2(BIN 源), D(字符串目标)
示例STR D0 D10 D20
步数7
FNCFNC 200
STR D0 D10 D20

DSTR — 32 位数值→字符串 ​

项目说明
格式DSTR S1(存位数的软元件), S2(BIN 源), D(字符串目标)
操作数S1(存位数的软元件), S2(BIN 源), D(字符串目标)
示例DSTR D0 D10 D20
步数13
FNCFNC 200 (D)
DSTR D0 D10 D20

VAL — 字符串→数值(BIN) ​

项目说明
格式VAL S(字符串), D1(存"位数"的软元件), D2(BIN 目标)
操作数S(字符串), D1(存"位数"的软元件), D2(BIN 目标)
示例VAL D0 D10 D20
步数7
FNCFNC 201
VAL D0 D10 D20

LEN — 求字符串长度 ​

项目说明
格式LEN 源 S, 目标 D
操作数源 S, 目标 D
示例LEN D0 D10
步数5
FNCFNC 203
LEN D0 D10

LEFT — 从左侧取子串 ​

项目说明
格式LEFT 源 S, 长度 n, 目标 D
操作数源 S, 长度 n, 目标 D
示例LEFT D0 K3 D10
步数7
FNCFNC 205
LEFT D0 K3 D10
项目说明
格式RIGHT 源 S, 长度 n, 目标 D
操作数源 S, 长度 n, 目标 D
示例RIGHT D0 K3 D10
步数7
FNCFNC 204
RIGHT D0 K3 D10

MIDR — 从中间读取子串 ​

项目说明
格式MIDR 源 S, 起始 n, 目标 D
操作数源 S, 起始 n, 目标 D
示例MIDR D0 K2 D10
步数7
FNCFNC 206
MIDR D0 K2 D10

MIDW — 从中间写入子串 ​

项目说明
格式MIDW 源 S, 起始 n, 目标 D
操作数源 S, 起始 n, 目标 D
示例MIDW D0 K2 D10
步数7
FNCFNC 207
MIDW D0 K2 D10

INSTR — 字符串检索(在 S1 中查找 S2 的位置) ​

项目说明
格式INSTR 源 S1, 检索 S2, 结果 D, 长度 n
操作数源 S1, 检索 S2, 结果 D, 长度 n
示例INSTR D0 D10 D20 K4
步数9
FNCFNC 208
INSTR D0 D10 D20 K4

FDEL — 删除表中指定位置的数据(后续数据前移),被删掉的值送到第一个操作数 ​

项目说明
格式FDEL D(取出值), S(表首址), n(删除位置)
操作数D(取出值), S(表首址), n(删除位置)
示例FDEL D0 D10 K3
步数7
FNCFNC 210
FDEL D0 D10 K3

FDEL 删除一条:被删的值送到 S,后续前移,表长那一格本机不改

FINS — 向表中指定位置插入数据(后续数据后移) ​

项目说明
格式FINS S(插入值), D(表首址), n(插入位置)
操作数S(插入值), D(表首址), n(插入位置)
示例FINS D0 D10 K3
步数7
FNCFNC 211
FINS D0 D10 K3

FINS 插入一条:后续数据后移,但表长那一格本机不改

SFL — 字左移(带进位):D 的 16 位整体左移 n 位,移出的最高位进 M8022 ​

项目说明
格式SFL D(数据), n(移位数 1~15)
操作数D(数据), n(移位数 1~15)
示例SFL D0 K3
步数5
FNCFNC 214
SFL D0 K3

SFL 单字左移:低位补 0,最后移出的一位送 M8022

SFR — 字右移(带进位):D 的 16 位整体右移 n 位,移出的最低位进 M8022 ​

项目说明
格式SFR D(数据), n(移位数 1~15)
操作数D(数据), n(移位数 1~15)
示例SFR D0 K3
步数5
FNCFNC 213
SFR D0 K3

SFR 单字右移:按有符号移,负数高位一直补 1

LPPLC 工业物联网云平台 · 软硬件与云平台全栈自研