- 1. 1. 先搞懂:get_xxx 不产生串口帧
- 2. 2. 位操作:set_bit / get_bit
- 3. 3. 16 位整型:set/get_uint16、set/get_int16
- 4. 4. 32 位:set/get_uint32、set/get_int32
- 5. 5. 64 位:set/get_uint64、set/get_int64
- 6. 6. 浮点:set/get_float、set/get_double
- 7. 7. 字符串:set/get_string
- 8. 8. 批量写:set_uint16_ex 与 set_array
- 9. 9. 完整示例:12 组数据类型复制
寄存器读写 API 是 LUA 和数据打交道的核心。以 DCBUS 为例,HMI 数据类型包括 bit、int16/uint16、int32/uint32、int64/uint64、float、double、string,还有批量写短整型。这篇把读写 API 全部讲透。
1. 先搞懂:get_xxx 不产生串口帧
所有 get_xxx() 函数都从 HMI 本地缓存(内存镜像)读取,不发起串口请求。HMI 后台任务按工程配置的轮询周期,自动从 PLC 读取 VT_0x/VT_1x/VT_3x/VT_4x 等通信变量并缓存;脚本调用 get_xxx 直接返回缓存值。
这意味着脚本层的读取是零通信开销的——不会因为脚本逻辑导致通信风暴。好处是系统实时性有保障,代价是读到的是”最近一次轮询”的值,不是绝对实时。

2. 位操作:set_bit / get_bit
set_bit(vtype, addr, value, count) -- 批量写位, count=1~16 get_bit(vtype, addr) -- 读单一位, 返回0/1
set_bit 的 value 是 16 位无符号值,其 bit0 对应 addr、bit1 对应 addr+1……count 指定写多少位(1~16)。适合 Modbus 线圈、FX3U 的 X/Y/S/M 位区。
示例:点击线圈 0x0000,自动把状态复制到线圈 0x0001:
function on_update(slave, vtype, addr)
if vtype == VT_0x then
if addr == 0x0000 then
set_bit(VT_0x, 0x0001, get_bit(VT_0x, 0x0000))
end
end
end

3. 16 位整型:set/get_uint16、set/get_int16
set_uint16(vtype, addr, value) -- 0~65535, 超出自动 value & 0xFFFF get_uint16(vtype, addr) -- 读16位无符号 set_int16(vtype, addr, value) -- -32768~+32767, 超出自动 value & 0xFFFF get_int16(vtype, addr) -- 读16位有符号
uint16 就是 Modbus 保持寄存器、FX3U D 寄存器、HMI 内部变量(LW)的基本单位。注意:int16 写入负值时存的是补码,读回用 get_int16 才还原成负数。
4. 32 位:set/get_uint32、set/get_int32
set_uint32(vtype, addr, value) -- 0~4294967295, 超出 & 0xFFFFFFFF, 地址跨度+2 get_uint32(vtype, addr) set_int32(vtype, addr, value) -- -2^31 ~ 2^31-1, 地址跨度+2 get_int32(vtype, addr)
32 位占连续 2 个寄存器。低地址是低位还是高位取决于 set_endian() 设置(默认小端,即低地址存低字节)。
5. 64 位:set/get_uint64、set/get_int64
set_uint64(vtype, addr, value) -- 0~2^64-1, 地址跨度+4 get_uint64(vtype, addr) set_int64(vtype, addr, value) -- -2^63 ~ 2^63-1, 地址跨度+4 get_int64(vtype, addr)
64 位占连续 4 个寄存器。电表、流量计这类大数场景用。
6. 浮点:set/get_float、set/get_double
set_float(vtype, addr, value) -- IEEE 754 单精度, 地址跨度+2 get_float(vtype, addr) set_double(vtype, addr, value) -- IEEE 754 双精度, 地址跨度+4 get_double(vtype, addr)
浮点按 IEEE 754 存储。例:get_float(VT_4x, 0x0064) 读保持寄存器 0x0064~0x0065 组成的单精度值。
7. 字符串:set/get_string
set_string(vtype, addr, str) -- 最大2KB, UTF-8或GBK get_string(vtype, addr, len) -- len默认128, 最大2048, 遇截断
字符串占连续寄存器(每寄存器 2 字节),地址跨度 = 字节数/2 向上取整。存中文注意编码要和 PLC 约定一致。
8. 批量写:set_uint16_ex 与 set_array
set_uint16_ex(vtype, addr, v1, v2, ..., vN) -- 最多120个寄存器, 可变参数 set_array(vtype, addr, buff) -- buff是Lua table, 最多120字
两者都能批量写,区别:set_uint16_ex 参数直接列在函数里,适合固定个数;set_array 传 Lua 表,适合程序化生成、动态数据。批量写能显著减少通信帧数。
9. 完整示例:12 组数据类型复制
官方例程在 on_update 里按类型把源地址复制到目标地址(vtype 判断 + addr 精确匹配):
function on_update(slave, vtype, addr)
if vtype ~= VT_LW then return end
if addr == 0x1000 then set_uint16(VT_LW, 0x1001, get_uint16(VT_LW, 0x1000)) end
if addr == 0x1002 then set_int16(VT_LW, 0x1003, get_int16(VT_LW, 0x1002)) end
if addr == 0x1004 then set_uint32(VT_LW, 0x1006, get_uint32(VT_LW, 0x1004)) end
if addr == 0x1008 then set_int32(VT_LW, 0x100A, get_int32(VT_LW, 0x1008)) end
if addr == 0x100C then set_uint64(VT_LW, 0x1010, get_uint64(VT_LW, 0x100C)) end
if addr == 0x1014 then set_int64(VT_LW, 0x1018, get_int64(VT_LW, 0x1014)) end
if addr == 0x101C then set_float(VT_LW, 0x101E, get_float(VT_LW, 0x101C)) end
if addr == 0x1020 then set_double(VT_LW, 0x1024, get_double(VT_LW, 0x1020)) end
if addr == 0x1030 then set_string(VT_LW, 0x1040, get_string(VT_LW, 0x1030)) end
-- 批量写: 0x1050为偶数时, 写10个寄存器
if addr == 0x1050 then
local v = get_uint16(VT_LW, 0x1050)
if v % 2 == 0 then
set_uint16_ex(VT_LW, 0x1060, 1,2,3,4,5,6,7,8,9,10)
end
end
-- set_array 写法: 写10,20,...,90,100
if addr == 0x1060 then
local t = {}
for i=1,10 do t[i] = i*10 end
set_array(VT_LW, 0x1070, t)
end
end
整理自 广州大彩科技 VisualHMI 开发文档(hmi-doc.gz-dc.com)LUA 教程「寄存器操作」,版权归大彩科技所有。
发表回复