菜单

寄存器操作函数

下载

适用版本:1.0.27 更新日期:2026-10-09

Lua 脚本通过本节接口读写工程变量。寄存器类型 vtype 表示变量存储区,数据类型则由函数名决定;两者不能混用。整数地址可以写为十进制,也可以使用 0x 开头的十六进制。

完整的四区字/位、功能码、批量读写、轮询及双从站示例见 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 类型表。

运行库没有预设 LW、RW、HOLDING 等 Lua 常量;需要时在自己的脚本中定义:

lua 复制代码
local LW = 1
local RW = 2
local HOLDING = 6

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

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

2. 数值读写函数

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

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

读函数 写函数 数据范围或表示 本地变量占用
get_uint16(vtype, addr) set_uint16(vtype, addr, value) 整数 0~65535 1 字
get_int16(vtype, addr) set_int16(vtype, addr, value) 整数 -32768~32767 1 字
get_uint32(vtype, addr) set_uint32(vtype, addr, value) 可直接传入和正常返回的非负整数 0~2147483647 2 字
get_int32(vtype, addr) set_int32(vtype, addr, value) 整数 -2147483648~2147483647 2 字
get_uint64(vtype, addr) set_uint64(vtype, addr, value) 可直接传入和正常返回的非负整数 0~2147483647 4 字
get_int64(vtype, addr) set_int64(vtype, addr, value) 可直接传入和正常返回的整数 -2147483648~2147483647 4 字
get_float(vtype, addr) set_float(vtype, addr, value) 32 位浮点数,约 7 位有效十进制数字 2 字
get_double(vtype, addr) set_double(vtype, addr, value) 寄存器为 64 位浮点格式,但 Lua 输入和输出仍只有 32 位浮点精度 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

3. 位读写

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 相邻位的批量写入。

4. 字符串

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

get_string 从起始字地址读取最多 64 个字,即 128 字节,遇到首个零字节结束并返回字符串;接近地址末端时只读取剩余范围。没有长度参数。读不到的部分不会继续读取,因此返回空字符串或较短字符串也不能证明外部设备在线。

set_string 接收最多 127 字节文本,加零结尾并按完整字对齐后写入,成功无返回值。限制按编码后的字节数计算,不是字符个数;UTF-8 中文通常占多个字节。按“前一字符在字的高字节、后一字符在低字节”的顺序写入,例如 AB 对应字 0x4142。不要在普通文本中插入零字节,否则读取会在该处结束。

lua 复制代码
local LW = 1

function on_init()
    set_string(LW, 0x1200, "Hello")
    local text = get_string(LW, 0x1200)
    print(text)
end

根据最长文本预留完整地址范围。PLC 字符串写入还受该驱动支持的数据区和单次容量限制;不是所有 PLC 软元件都支持字符串。

5. 连续数组写入

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,不要把它与寄存器字数组混用。

6. 选择从站和持续预读

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 接口。脚本关闭或重载会清理旧脚本的预读范围,控件自身的轮询独立保留。首次预读登记成功不代表已经收到从站应答。

7. 变量更新回调

脚本可定义 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,回调返回值不能撤销写入。

8. 控制自动上传:set_notify

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_* 仍进入主站写队列;要暂停这类发送,应停止或限制脚本中的写操作。暂停定时写入见定时器函数。

9. 常见错误

  • 使用未定义的 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
上一个
系统回调函数
下一个
自由协议串口函数
最近修改: 2026-10-09Powered by