全部手册
SIMTUTAI / DOCUMENTATION

开发手册

开发手册、使用视频,应用案例。

Lua 脚本用于读写本地 LW、掉电保存 RW 及外部 PLC 变量。vtype 选择存储区,函数名决定数据格式。

核心功能

  • 数值、位、字符串及连续数组读写。
  • Modbus、FX、DVP、XC、XD 地址映射。
  • 从站选择、持续预读与变量更新通知。

完整的四区操作与双从站示例见 5.6 Modbus 读写。

1. 地址与类型

变量类型 vtype 地址说明
LW 本地变量 1 字地址 0x0000~0xFFFF
RW 掉电保存变量 2 字地址 0x0000~0x7FFF
Modbus 0x 线圈 3 每地址一个位,使用工程配置的数值地址
Modbus 1x 离散输入 4 每地址一个位;主站访问外部设备时只读
Modbus 3x 输入寄存器 5 每地址一个 16 位字;主站访问外部设备时只读
Modbus 4x 保持寄存器 6 每地址一个 16 位字,使用工程配置的数值地址

屏作为 Modbus Slave 时,屏内 Lua 可以更新 1x/3x 输入数据,供外部主站读取;外部主站仍不能经写功能码写入这两个区。

Modbus 使用数值地址,例如保持寄存器地址 100 写作 get_uint16(6, 100),不能仅凭设备标签 40101 就把 40101 直接代入。FX、DVP、信捷等 PLC 的 vtype 和地址范围按各自协议的软元件映射选择,不能套用 Modbus 类型表。

运行库没有预设 VT_*、LW、RW 等 Lua 常量;请先添加公共定义,再选择与工程通信协议一致的一段。

数值和位读取函数成功时返回一个数值,字符串读取返回字符串。set_* 成功时没有返回值;数值读写、位读写及写入接口在参数错误、地址或类型不支持、读写失败时抛 Lua 错误,可以用 pcall 捕获。字符串读取规则见“2.3 字符串”。不能通过 set_uint16(...) == 0 判断成功。

主站 get_* 读取运行库中的缓存,调用后不会同步等待 PLC 应答。主站 set_* 校验通过后先提交本地可读值,再尝试发送 PLC 命令;函数正常返回或触发 on_update,均不等于 PLC 已执行。首次缓存值也不能作为设备在线的判断依据。

地址参数使用工程的数值索引。例如 D100 的 addr 是 100;X/Y 的手册编号可能采用八进制表示,脚本应使用工程已经换算后的索引,不把手册标签数字直接作为索引,也不在运行库收到索引后再转换一次。

1.1 公共定义

在 main.lua 顶部先放公共定义,再从 1.2~1.6 中选择与工程通信协议对应的一段。下面使用全局 VT_名称 = 编号、十进制编号和中文注释,便于在各业务回调中直接引用。

lua 复制代码
--数据类型定义
--VTYPE
VT_LW = 1    --变量地址,屏内LW
VT_RW = 2    --FLASH存储,屏内RW

LW = VT_LW   --兼容旧脚本:变量地址
RW = VT_RW   --兼容旧脚本:FLASH存储

VT_* 表示寄存器区域;get_uint16、get_int32、get_float 等函数名决定数值格式。常量必须先定义再使用,Lua 区分大小写,例如 VT_0x 中的 x 为小写。

不同协议的定义只选一段,不要同时粘贴。 例如 D 区在 FX 中是 10、DVP 中是 11、信捷 XC 中是 9、信捷 XD 中是 17。同名常量后定义会覆盖前定义,常量赋值不会自动切换工程通信协议。

下列编号表示当前运行库识别的区域,不代表每一种 PLC 型号都具备全部区域或容量。地址范围、写权限和通信参数须与工程及实际设备一致。

1.2 Modbus RTU 主站/从站

lua 复制代码
--Modbus寄存器类型
VT_0x = 3    --线圈,位区
VT_1x = 4    --输入点,位区
VT_3x = 5    --输入寄存器,16位字区
VT_4x = 6    --保持寄存器,16位字区

主站访问外部设备时,1x、3x 只读;0x、4x 可写。屏作为 Modbus 从站时,Lua 可以更新屏内四个区域,包括 1x、3x;外部主站仍不能通过写功能码写输入区。

lua 复制代码
--写法示例:在业务需要时调用
-- get_bit(VT_0x, 0)             --读取地址0的线圈
-- set_bit(VT_0x, 0, 1)          --地址0的线圈置1
-- get_uint16(VT_4x, 100)        --读取保持寄存器地址100
-- set_uint16(VT_4x, 100, 123)   --保持寄存器地址100写入123

addr 使用工程配置的数值地址,不把设备标签 40001 默认当成第一个地址。单点用 get_bit/set_bit;Modbus 位区的 get_uint16/set_uint16 会访问连续 16 点,不能用于代替单点操作。

1.3 三菱 FX2N/FX3U

lua 复制代码
--三菱FX寄存器类型
VT_X  = 3     --输入继电器,位区
VT_Y  = 4     --输出继电器,位区
VT_S  = 5     --状态继电器,位区
VT_M  = 6     --辅助继电器,位区
VT_SM = 7     --特殊辅助继电器,位区;当前FX2N不支持此独立区域
VT_TS = 8     --定时器触点状态,位区;当前FX2N不支持
VT_CS = 9     --计数器触点状态,位区;当前FX2N不支持
VT_D  = 10    --数据寄存器,16位字区
VT_SD = 11    --特殊数据寄存器,16位字区;当前FX2N不支持此独立区域
VT_R  = 12    --文件寄存器,16位字区;当前FX2N不支持
VT_T  = 13    --定时器当前值,16位字区
VT_C  = 14    --计数器当前值,16位字区
VT_CX = 15    --32位计数器当前值,索引0~55对应C200~C255

FX2N、FX3U 共用以上编号,不能删掉不支持的区域后把后续编号前移。FX2N 的特殊继电器、特殊数据寄存器通过 VT_M 的 8000 段、VT_D 的 8000 段访问;具体地址以设备型号为准。

TS/CS 是触点状态,T/C 是当前值。get_int32(VT_CX, 0) 对应 C200 的完整 32 位计数值,索引应传 0,不是 200。FX 当前从站选择只支持 select_slave(0)。X 为输入状态,实际写权限以 PLC 为准。

1.4 台达 DVP

lua 复制代码
--台达DVP寄存器类型
VT_S  = 3     --步进继电器,位区
VT_X  = 4     --输入继电器,位区,只读
VT_Y  = 5     --输出继电器,位区
VT_T  = 6     --定时器触点状态,位区
VT_M  = 7     --辅助继电器,位区
VT_C  = 8     --计数器触点状态,位区
VT_TV = 9     --定时器当前值,16位字区
VT_CV = 10    --计数器当前值,位宽见下文
VT_D  = 11    --数据寄存器,16位字区

T/C 是状态,TV/CV 是当前值。CV0~199 为 16 位,CV200~255 每个计数器为原生 32 位,地址步长仍为 1;例如 get_uint16(VT_CV, 199) 与 get_int32(VT_CV, 200)。不要用 16 位接口读取 CV200~255。

当前 DVP 使用 Modbus ASCII。位元件用 get_bit/set_bit,一个地址对应一个位;数值通路支持 16/32 位整数和 32 位浮点,不应直接套用通用 64 位接口。

1.5 信捷 XC

lua 复制代码
--信捷XC寄存器类型
VT_X  = 3     --输入点,位区,只读
VT_Y  = 4     --输出点,位区
VT_M  = 5     --辅助继电器,位区
VT_S  = 6     --流程继电器,位区
VT_T  = 7     --定时器状态,位区
VT_C  = 8     --计数器状态,位区
VT_D  = 9     --数据寄存器,字区
VT_TD = 10    --定时器当前值,字区
VT_CD = 11    --计数器当前值,字区
VT_FD = 12    --FLASH寄存器,字区

XC 使用 Modbus RTU。T/C 是状态,TD/CD 是当前值。读取 D100 写作 get_uint16(VT_D, 100);M0 使用 get_bit(VT_M, 0)。

1.6 信捷 XD

lua 复制代码
--信捷XD寄存器类型
VT_M    = 3     --辅助继电器,位区
VT_X    = 4     --输入点,位区,只读
VT_Y    = 5     --输出点,位区
VT_S    = 6     --流程继电器,位区
VT_SM   = 7     --特殊继电器,位区,当前驱动只读
VT_T    = 8     --定时器状态,位区
VT_C    = 9     --计数器状态,位区
VT_ET   = 10    --精确定时器状态,位区
VT_SEM  = 11    --顺序功能块专用区域,位区,当前驱动只读
VT_HM   = 12    --保持型辅助继电器,位区
VT_HS   = 13    --保持型流程继电器,位区
VT_HT   = 14    --保持型定时器状态,位区
VT_HC   = 15    --保持型计数器状态,位区
VT_HSC  = 16    --高速计数器状态,位区
VT_D    = 17    --数据寄存器,字区
VT_ID   = 18    --输入寄存器,字区,只读
VT_QD   = 19    --输出寄存器,字区
VT_SD   = 20    --特殊数据寄存器,字区,当前驱动只读
VT_TD   = 21    --定时器当前值,字区
VT_CD   = 22    --计数器当前值,字区
VT_ETD  = 23    --精确定时器当前值,字区
VT_HD   = 24    --保持型数据寄存器,字区
VT_HSD  = 25    --保持型特殊寄存器,字区
VT_HTD  = 26    --保持型定时器当前值,字区
VT_HCD  = 27    --保持型计数器当前值,字区
VT_HSCD = 28    --高速计数器当前值,字区
VT_FD   = 29    --FLASH寄存器,字区
VT_SFD  = 30    --特殊FLASH寄存器,字区,当前驱动只读
VT_FS   = 31    --特殊保密寄存器,字区,部分资料称FSD

XD 使用 Modbus RTU。XC 的 D 区编号是 9,XD 的 D 区编号是 17,不能混用。 当前 XD 的 SM/SEM/SD/SFD 按只读处理;未开放字符串及 64 位数据类型。

XC/XD 字区按 Modbus 字地址访问。普通 D 区的 32 位整数、浮点数占两个连续字,字节序取工程协议配置;不要由 PLC 计数器名称推断成台达 DVP 的原生 32 位计数器访问规则。

2. 接口说明

2.1 数值读写

当前工程 Lua 使用 32 位有符号整数和 32 位浮点数。函数名中的 32/64 位描述寄存器的存储格式,不会扩大 Lua 的数值范围;64 位寄存器接口也不能直接接收任意 64 位整数。

这些函数的完整签名为 get_类型(vtype, addr) 和 set_类型(vtype, addr, value)。没有可选的位序、从站、字节序或通知参数;选择从站使用 select_slave,通知参数仅属于后面的 set_bit。

读函数 写函数 Lua 数值范围/精度 占用
get_uint16 set_uint16 整数 0~65535 1 字
get_int16 set_int16 整数 -32768~32767 1 字
get_uint32 set_uint32 0~2147483647 2 字
get_int32 set_int32 整数 -2147483648~2147483647 2 字
get_uint64 set_uint64 0~2147483647 4 字
get_int64 set_int64 -2147483648~2147483647 4 字
get_float set_float 32 位浮点数,约 7 位有效十进制数字 2 字
get_double set_double 64 位存储,Lua 仍为单精度 4 字

vtype 和 addr 必须为整数;整数写函数的 value 也必须为整数。浮点写函数接收数值。地址跨度不得回绕,例如从 0xFFFF 起只能读写 1 个本地字,不能存储 32 位或 64 位值。不同 PLC 的原生元素宽度、读写权限和数据类型支持仍以该协议为准。

本地 LW/RW 的多字数值按高字在前保存;PLC 的数值字节序使用工程中对应协议的设置。完整的 UINT32/UINT64/INT64 存储范围超过当前 Lua 整数范围:读取超出上表范围的值时,可能出现高位截断或符号变化;get_uint64 仅在原始值超过 0x7FFFFFFFFFFFFFFF 时另行报错,不能用它自动检测所有 Lua 范围溢出。

需要保留完整的较大整数时,可在 LW/RW 或普通 16 位字寄存器中按字读取,再分别处理各字;不要把超范围的整数文本转成 Lua 数值后写入。PLC 原生 32 位软元件应按该协议的元素规则处理,不能直接套用连续 LW 字的拆分例子。没有注册 get_uint8、set_uint8、get_int8 或 set_int8 接口。

下面在相互独立的地址保存不同类型,再读取:

lua 复制代码
local LW = 1

function on_init()
    set_uint16(LW, 0x1014, 9)
    set_int16(LW, 0x1020, -9)
    set_uint32(LW, 0x1030, 70000)
    set_int32(LW, 0x1040, -70000)
    set_uint64(LW, 0x1050, 1234567)
    set_int64(LW, 0x1060, -1234567)
    set_float(LW, 0x1070, 12.5)
    set_double(LW, 0x1080, 12.5)

    print(get_uint16(LW, 0x1014))
    print(get_int16(LW, 0x1020))
    print(get_uint32(LW, 0x1030))
    print(get_int32(LW, 0x1040))
    print(get_uint64(LW, 0x1050))
    print(get_int64(LW, 0x1060))
    print(get_float(LW, 0x1070))
    print(get_double(LW, 0x1080))
end

例如用两个本地字保留完整 0xFFFFFFFF,不把它当成一个 Lua 非负整数:

lua 复制代码
local LW = 1

function write_large_unsigned_value()
    set_uint16_ex(LW, 0x1090, {0xFFFF, 0xFFFF})
    local high = get_uint16(LW, 0x1090)
    local low = get_uint16(LW, 0x1091)
    print(string.format("%04X%04X", high, low))
end

2.2 位读写

lua 复制代码
get_bit(vtype, addr)
set_bit(vtype, addr, value)
set_bit(vtype, addr, value, notify)

get_bit 返回 0 或 1。set_bit 的 value 只能是整数 0 或 1,成功无返回值。参数中的 addr 是相应变量地址,没有额外的位索引参数;在 LW/RW 字变量上,这两个接口读取或修改该字的第 0 位。

Modbus 类型 3/4 中,get_bit/set_bit 访问地址所指的单点,get_uint16/set_uint16 则访问连续 16 点;例如 set_uint16(3, 0x224, 1) 会把随后 15 点写为 0,单线圈应使用 set_bit(3, 0x224, 1)。类型 5/6 的 get_bit 读取字内 bit0,主站 set_bit(6, ...) 按已确认缓存合并后发送完整字,须先建立有效读回,不提供 PLC 原子掩码写。任意字内位及字段的辅助函数见专门示例。

notify 作用
0 当前写入不产生本地 on_update 通知,也不请求主动协议上传
1 默认值:正常变量更新通知,并请求协议通知
2 正常变量更新通知,不请求主动协议上传

主动协议上传指 DCBUS/DGUS 的自动上传,仍受工程“自动上传”设置及 set_notify 开关影响。notify=0/2 不会阻止 Modbus、FX、DVP、XC、XD 等主站向外部寄存器发送写命令。外部 PLC 后续真实应答或读回属于独立的缓存更新,不受此前静默写入的限制。需要操作一个 LW 字的其他位时,可先读取完整字,用 Lua 位运算修改,再用 set_uint16 写回:

lua 复制代码
local LW = 1

function on_init()
    set_bit(LW, 0x1100, 1, 2)
    print(get_bit(LW, 0x1100))

    local value = get_uint16(LW, 0x1101)
    set_uint16(LW, 0x1101, value | (1 << 3))
end

PLC 位软元件使用该协议自己的位地址,不把上面的本地字位运算当作 PLC 相邻位的批量写入。

2.3 字符串

读取和写入

lua 复制代码
local text = get_string(vtype, addr)
set_string(vtype, addr, text)

vtype 为寄存器类型:1 表示 LW,2 表示 RW;addr 为起始字地址,例如 0x1000 对应工程中的 LW1000。get_string 没有长度参数,返回字符串;set_string 成功无返回值,参数、长度、地址跨度或写入失败时抛出 Lua 错误。

下面以 LW 为例,脚本保存为 UTF-8;实际工程请把示例地址改为已预留的空闲地址。各示例分别使用;工程已有 on_init() 时,把初始化代码合并到原函数,不要重复定义。

lua 复制代码
local LW = 1

function on_init()
    -- 写入字符串到 LW1000
    set_string(LW, 0x1000, "你好,鑫通态")

    -- 读取 LW1000 的字符串
    local text = get_string(LW, 0x1000)
    print(text)
end

拼接后写回

Lua 使用 .. 拼接字符串。拼接后先检查字节数,避免超过写入上限:

lua 复制代码
local LW = 1
local text = get_string(LW, 0x1000)
local result = text .. ",运行正常"

if #result <= 127 then
    set_string(LW, 0x1000, result)
else
    print("字符串超过127字节")
end

这里的 #result 是字节数,不是中文字符个数。不要直接截取前 127 字节来处理超长中文,否则可能截断一个 UTF-8 字符。

清空字符串

lua 复制代码
set_string(1, 0x1000, "")

写入空字符串后,get_string(1, 0x1000) 返回 ""。此操作把起始字写为零,使文本内容为空,不会擦除整个预留区的旧数据。

长度、寄存器空间和中文显示

  • 写入最多 127 字节。 接口自动补零结束符,并按完整的 16 位字对齐;占用字数为 math.floor(#text / 2) + 1。
  • 为字符串预留连续地址。 若需要支持最大长度,应预留 64 个寄存器,例如 LW1000~LW103F(0x1000~0x103F),这段地址不要再放其他变量。短字符串只写入所需字数。
  • 读取最多 64 个字,即 128 字节。 返回内容在首个零字节处结束;接近地址末端时只读剩余范围。读取失败时可能返回空串或已读到的较短字符串,不能据此判断外部设备在线。
  • 接口不做编码转换。 中文按 Lua 字符串原有字节保存,UTF-8 中文通常占多个字节;不要在普通文本中插入零字节。
  • 文本控件需匹配编码和字内顺序。 上述例子使用 UTF-8;控件也选择 UTF-8,并使字内顺序与 Lua 写入一致。可先写入 AB 验证,控件应显示 AB,而不是 BA。

本地 LW/RW 按每字高字节在前保存文本字节:"A" 占 1 个字(0x4100),"AB" 占 2 个字(0x4142、0x0000)。

PLC 字符串读写还受驱动的数据区、缓存和字节序设置影响,不是所有 PLC 软元件都支持字符串;不要直接把上述 LW 示例视为已验证的外部 PLC 字符串方案。

2.4 连续数组

lua 复制代码
set_uint16_ex(vtype, addr, values)
set_array(vtype, addr, values)

两者功能相同:values 为从下标 1 开始、没有空洞的整数表,长度为 1~2000,每项表示一个 16 位字,按连续地址写入。每项请使用 0~65535 的整数;成功无返回值。它们不是 8 位字节数组接口,没有对应的 get_array 原生接口。

lua 复制代码
local LW = 1

function on_init()
    set_uint16_ex(LW, 0x1014, {9, 0, 9})
    -- LW1014=9,LW1015=0,LW1016=9。

    set_array(LW, 0x1300, {0x1234, 0x5678})
    for i = 0, 1 do
        print(get_uint16(LW, 0x1300 + i))
    end
end

字表提交原始 16 位字,不执行单值数值接口的 16 位整序交换;超范围表项当前会截断为 UINT16,应在调用前检查。Modbus 线圈字表每项覆盖 16 点,{1, 0, 1} 表示 48 点,不是三个单点;具体保尾及分帧规则见专门示例。

数组跨度不能越过地址末端,PLC 后端也可能因设备区、只读范围或缓存容量拒绝。需要发送原始字节表时使用 uart_send,不要把它与寄存器字数组混用。

2.5 从站与预读

lua 复制代码
select_slave(slave_index)
start_read(slave_index, vtype, addr, count)

slave_index 是工程配置中的从站索引,从 0 开始,不是设备通信站号。默认选择索引 0;例如第二个配置从站的站号是 7,仍应使用 select_slave(1)。索引必须为已配置的 0~7,FX 只支持 0;非法选择会抛错误并保留此前选择。选择影响后续数值、位、字符串及数组读写,LW/RW 仍使用本地数据区。

start_read 登记持续轮询范围,成功无返回值,不同步返回数据。通常在脚本顶层或 on_init 登记一次,换页和通信重配会恢复登记,不需要每次 on_run 重复登记。

count 为整数 1~65535,且 addr + count <= 65536;最多保留 16 个不同的“从站索引 + 类型 + 起始地址”范围,同一起点再次调用会修改数量。Modbus 字区以 16 位字计数;Modbus 类型 3/4 延续寄存器桥接语义,每个登记字覆盖最多 16 个位。LW/RW 不登记外部轮询,也不消耗范围槽位。PLC 仍受工程地址范围、设备原生元素宽度和驱动容量限制。

lua 复制代码
local HOLDING = 6

function on_init()
    select_slave(0)
    start_read(0, HOLDING, 100, 10)
    set_run_cycle(100)
end

function on_run(screen)
    local value = get_uint16(HOLDING, 100)
    print("page", screen, "cached value", value)
end

没有注册名为 poll_register 或 stop_read 的 Lua 接口。脚本关闭或重载会清理旧脚本的预读范围,控件自身的轮询独立保留。首次预读登记成功不代表已经收到从站应答。

2.6 变量更新

脚本可定义 on_update(slave, vtype, addr)。运行库在可读缓存更新后调用;slave 是从站索引,本地 LW/RW 为 0,addr 是实际更新的地址。使用相应 get_* 读取最新值:

lua 复制代码
local LW = 1

function on_update(slave, vtype, addr)
    if vtype == LW and addr == 0x1014 then
        local value = get_uint16(LW, addr)
        print("temperature", value)
    end
end

相同值通常不重复通知,外部源首次有效零值也会通知;同一地址分发前的多次变化可能合并为一次。多字值可能按组成它的多个寄存器通知。回调中同步写变量不会递归触发新的 on_update,回调返回值不能撤销写入。

2.7 自动上传

lua 复制代码
set_notify(enable)

enable 必须是整数 0 或 1,成功无返回值。默认开启;set_notify(0) 关闭 DCBUS/DGUS 自动上传,set_notify(1) 恢复后续自动上传。它作用于 Lua set_*、控件通知及系统复制触发的自动上传,仍需在工程中开启“自动上传”。

lua 复制代码
local LW = 1

function update_demo_value()
    set_notify(0)
    set_uint16(LW, 0x2100, 123)
    set_notify(1)
end

关闭时仍更新本地值、控件显示及相应 on_update;恢复后不会补发关闭期间的数据。脚本关闭、重载或加载失败时,运行库会在脚本资源和终结器清理完成后恢复默认开启。

此接口不是整个串口的停发开关。 它不停止协议应答、PLC 主站轮询、主动 uart_send、独立第二串口或串口下载。Modbus、FX、DVP、XC、XD 等外部寄存器的 set_* 仍进入主站写队列;要暂停这类发送,应停止或限制脚本中的写操作。暂停定时写入见5.4 定时器。

3. 应用

3.1 读取 XD 寄存器

下面是信捷 XD 的完整示例,选择第一个配置从站,每 200 ms 读取 D100 和 M0,仅在值变化时打印。工程已有 on_init/on_run 时,把内容合并到原回调,不要重复定义。

lua 复制代码
--信捷XD示例;工程通信协议须选择信捷XD
VT_LW = 1
VT_RW = 2
VT_M = 3
VT_D = 17
LW = VT_LW
RW = VT_RW

local d100 = nil
local m0 = nil

function on_init()
    select_slave(0)             --第一个配置从站,不是PLC站号0
    set_run_cycle(200)
    start_read(0, VT_D, 100, 1)  --D100,一个16位字
    start_read(0, VT_M, 0, 1)    --M0,一个位元件

    --按业务需要放入已有回调;以下写入默认不执行
    -- set_uint16(VT_D, 100, 123)
    -- set_bit(VT_M, 0, 1)
end

function on_run(screen)
    select_slave(0)

    --首次尚无有效数据时可能读取失败,保留nil,不当作0
    local ok_d, value_d = pcall(get_uint16, VT_D, 100)
    local ok_m, value_m = pcall(get_bit, VT_M, 0)

    if ok_d and value_d ~= d100 then
        d100 = value_d
        print("D100 =", d100)
    end

    if ok_m and value_m ~= m0 then
        m0 = value_m
        print("M0 =", m0)
    end
end

换成 XC 时,上述示例的 VT_M 改为 5、VT_D 改为 9,并在工程中选择信捷 XC。其他协议使用各自的定义和原生元素规则,不能照搬本例的位区预读计数。

get_* 读取 HMI 缓存,不同步等待 PLC,应答尚未到达时可用 pcall 捕获读取错误。通信中断后缓存可能仍保留旧值;set_* 正常返回或触发 on_update 表示本地可读值已提交,不代表 PLC 已确认执行,也不能据此判断在线。

4. 常见问题

现象 检查方法
使用未定义的 LW 常量 在脚本中先写 local LW = 1,或者直接传整数 1
给整数函数传小数、布尔值或字符串 使用对应整数值;浮点数使用 set_float 或 set_double
忽略 32/64 位的连续地址 为数据预留 2/4 个字,避免覆盖旁边的变量
把从站索引当站号,或把读缓存当同步读 按工程配置选择索引,使用持续预读与更新回调
为 get_string 传长度、为 set_uint16 多传通知参数 签名不支持这些参数
将成功无返回值误判为失败 需要捕获错误时使用下面写法

捕获写入错误

lua 复制代码
local ok, err = pcall(set_uint16, 1, 0x1014, 9)
if not ok then
    print("write failed", err)
end