14 LUA MODBUS应用
用户使用Modbus协议时,可以通过LUA交互实现复杂的逻辑,提供丰富的modbus接口函数,如下所示
序号 | 描述/API | 功能码 | 应用范围 |
---|---|---|---|
1 | 获取变量值:get_variant(name) | - | Fx2n/Xgus/Modbus |
2 | 设置变量值:set_variant(name,value) | - | Fx2n/Xgus/Modbus |
3 | 读线圈变量:mb_read_coil_01 (slave,addr,quantity) | 0x01 | Modbus |
4 | 读离散变量:mb_read_input_02(slave,addr,quantity) | 0x02 | Modbus |
5 | 读保存寄存器:mb_read_reg_03(slave,addr,quantity) | 0x03 | Modbus |
6 | 读输入寄存器:mb_read_input_reg_04(slave,addr,quantity) | 0x04 | Modbus |
7 | 写单个线圈:mb_write_coil_05 (slave,addr,status) | 0x05 | Modbus |
8 | 写单个保存寄存器:mb_write_reg_06 (slave,addr,reg) | 0x06 | Modbus |
9 | 写多个线圈:mb_write_coil_15 (slave,addr,quantity,coils) | 0x0F | Modbus |
10 | 写多个保存寄存器:mb_write_reg_16 (slave,addr,regs) | 0x10 | Modbus |
更多组态配置Modbus、变量的创建请参考Modbus教程,本章节不在阐述。本章节屏幕作为modbus 主站,创建线圈、离散输入、保存寄存器、输入寄存器各2个变量,具体属性可查看工程源文件,如下所示
本章节主要描述以下内容:
- 变量名读写值
- 线圈读写
- 读离散变量
- 保存寄存器读写
- 读输入寄存器
适用范围:M系列、W系列、X系列、F系列(固件版本 >= V4.2.401.0)
例程下载链接:《LUA - Modbus API 应用》(点击跳转)
特别说明:本例程的演示,由虚拟屏和Modbus Slave联调,第三方工具Modbus Slave、虚拟串口具体的使用、获取等,本章节不在阐述,在我司官网下载或自行网上下载
14.1 变量名读写值
get_variant(name) / set_variant(name, value)函数适用于在【工具】→【协议与变量…】里面创建的变量,不局限与Modbus,同时适用于三菱Fx2n、Xgus等协议,用法一样,参考本章节即可
函数说明
读变量:get_variant(name)
name:字符串,变量名,应用变量时候一定要和【工具】→【协议与变量…】里面创建的变量一致
eg:local data = get_variant(“设置温度”)
写变量:set_variant(name,value)
name:字符串,变量名,应用变量时候一定要和【工具】→【协议与变量…】里面创建的变量一致
value:数值
eg:M系列屏幕 feed_dog()--喂狗 set_variant(“设置温度”,25)
如上所示:实际项目中使用set_variant时,建议加上喂狗,避免从站不在线或其他不应答时候,发送3次写指令,导致看门狗复位。若屏幕型号为物联网,喂狗参考API说明 → 1.30.20使用。
画面配置
变量名读写是通过get_variant(name) / set_variant(name)函数来实现,画面配置如下所示
线圈的读写:
- 按钮控件ID1:作为读取“电源/开机”的触发按钮,并将值显示在文本控件ID2中
- 文本控件ID2:显示get_variant(“电源/开机”)获取后的值
- 按钮控件ID3:作为写“电源/开机”的触发按钮,将获取文本控件ID4的值在写入
- 文本控件ID4:键值输入“电源/开机”的目标值
保存寄存器的读写:
- 按钮控件ID5:作为读取“目标温度”的触发按钮,并将值显示在文本控件ID6中
- 文本控件ID6:显示get_variant(“设置温度”)获取后的值
- 按钮控件ID7:作为写“设置温度”的触发按钮,将获取文本控件ID8的值在写入
- 文本控件ID8:键值输入“设置温度”的目标值
LUA脚本
按钮控件ID1按下时,将“电源/开机”显示在文本控件ID1中,同理其他按钮/文本对应控件联动触发、显示,LUA脚本如下所示:
--用户通过触摸修改控件后,执行此回调函数。
--点击按钮控件,修改文本控件、修改滑动条都会触发此事件。
function on_control_notify(screen,control,value)
if screen == sc_variant
then
if control == 1 and value == 0
then
local power = get_variant('电源/开机')
set_value(sc_variant, 2, power)
elseif control == 3 and value == 0
then
local power = get_value(sc_variant, 4)
set_variant('电源/开机', power)
elseif control == 5 and value == 0
then
local dstTempe = get_variant('设置温度')
set_value(sc_variant, 6, dstTempe)
elseif control == 7 and value == 0
then
local dstTempe = get_value(sc_variant, 8)
set_variant('设置温度', dstTempe)
end
......
end
end
运行预览
根据画面配置和LUA脚本,运行结果如下所示
14.2 线圈(0x01,0x05,0x0F)
线圈的读写还可以通过mb函数来实现
函数说明
读取线圈:mb_read_coil_01 (slave,addr,quantity)
- salve:从机站号
- addr:线圈起始地址
- quantity:读取的个数
读取成功:返回字节数组,8个线圈为一个字节;读取失败,返回nil
如:从0开始,读取32个线圈,local coilsTb = mb_read_coil_01 (1, 0, 32)
假设读取成功,返回的字节内容依次为 coilsTb[0]=0x12,coilsTb[1]=0x24,coilsTb[1]=0x0C,coilsTb[1]=0x08线圈和字节数组的每一位的对应关系,如下所示
写单个线圈:mb_write_coil_05(slave,addr,state)
- salve:从机站号
- addr:线圈地址
- state:线圈状态,0或1
写成功,返回ture;写失败,返回false;
写多个线圈:mb_write_coil_15 (slave,addr,quantity,coils)
- salve:从机站号
- addr:线圈地址
- quantity:读取的个数
- coils:字节数组,设置的值,关系可参考上表
写成功,返回ture;写失败,返回false;
画面配置
通过mb函数来实现,画面配置如下所示
读线圈:
- 按钮控件ID1:作为读取“线圈”的触发按钮,并将值显示在文本控件ID2、ID4中
- 文本控件ID2:显示mb_read_coil_01(,,,)获取变量“电源”的值(coil1~coil16)
- 按钮控件ID4:显示mb_read_coil_01(,,,)获取变量“模式”的值(coil17~coil32)
设置单个线圈 “电源/开机”:
- 按钮控件ID5:设置线圈“电源/开机” = 1的触发按钮
设置多个线圈 “电源/开机”、“指示灯开关”:
- 按钮控件ID7:设置线圈“电源/开机” = 1、“指示灯开关” = 1的触发按钮
LUA脚本
按钮控件ID1按下时,将“电源”、“模式”显示在文本控件ID2、文本控件ID4中,同理其他按钮/文本对应控件联动触发、显示,LUA脚本如下所示:
--设置位函数
--data:源数据
--bitmask:第几位位置
--state:数值,0或1
function set_bits(data, bitmask, state)
bitmask = (1 << bitmask) & 0xFF
if state == 0
then
data = data & (~bitmask)
elseif state == 1
then
data = data | bitmask
end
print(data)
return data
end
--用户通过触摸修改控件后,执行此回调函数。
--点击按钮控件,修改文本控件、修改滑动条都会触发此事件。
function on_control_notify(screen,control,value)
......
elseif screen == sc_coils
then
if control == 1 and value == 1
then
local power, mode = 0, 0
--modbus coils: 请求从站号1,从地址0开始的32个线圈
local coilsTb = mb_read_coil_01(1, 0, 32)
if coilsTb ~= nil
then
power = (coilsTb[1] << 8) | coilsTb[0]
mode = (coilsTb[3] << 8) | coilsTb[2]
print('power = '..power)
print('mode = '..mode)
set_text(sc_coils, 2, power)
set_text(sc_coils, 4, mode)
end
elseif control == 5
then
mb_write_coil_05(1, 0, value)
elseif control == 7 and value == 0
then
local power = 0
local mode = 0
--modbus read coils: 读从站号1,从地址0开始的32个线圈
local coilsTb = mb_read_coil_01(1, 0, 32)
if coilsTb ~= nil
then
coilsTb[0] = set_bits(coilsTb[0], 0, 1) --设置“开机-电源”= 1
coilsTb[2] = set_bits(coilsTb[2], 6, 1) --设置“状态-打开指示灯” = 1
--modbus write coils:
mb_write_coil_15 (1, 0, 32, coilsTb)
end
end
......
end
end
运行预览
根据画面配置和LUA脚本,运行结果如下所示
14.3 离散输入(0x02)
函数说明
读取离散输入:mb_read_input_02(slave,addr,quantity)
- salve:从机站号
- addr:离散输入寄存器的起始地址
- quantity:读取的个数
读取成功:字节数组,8个离散输入为一个字节;读取失败,返回nil
如:从0开始,读取32个离散输入,local discreteTb = mb_read_input_02 (1, 0, 32)
离散变量和字节数组的每一位的对应关系可参考线圈说明
画面配置
通过mb函数来实现【离散输入】寄存器的读取,画面配置如下所示
读离散输入寄存器:
- 按钮控件ID1:作为读取离散输入寄存器“状态”、“告警”的触发按钮,并将值显示在文本控件ID2、ID4中
- 文本控件ID2:显示mb_read_input_02(,,,)获取变量“状态”的值(discrete1~discrete16)
- 文本控件ID4:显示mb_read_input_02(,,,)获取变量“告警”的值(discrete17~discrete32)
LUA脚本
按钮控件ID1按下时,将“状态”、“告警”显示在文本控件ID2、文本控件ID4中,LUA脚本如下所示
--用户通过触摸修改控件后,执行此回调函数。
--点击按钮控件,修改文本控件、修改滑动条都会触发此事件。
function on_control_notify(screen,control,value)
......
elseif screen == sc_discrete
then
if control == 1 and value == 1
then
local status, alert = 0, 0
--modbus coils: 请求从站号1,从地址0开始的32个线圈
local discreteTb = mb_read_input_02(1, 0, 32)
if discreteTb ~= nil
then
status = (discreteTb[1] << 8) | discreteTb[0]
alert = (discreteTb[3] << 8) | discreteTb[2]
print('status = '..status)
print('alert = '..alert)
set_text(sc_discrete, 2, status)
set_text(sc_discrete, 4, alert)
end
end
......
end
运行预览
根据画面配置和LUA脚本,运行结果如下所示
14.4 保存寄存器(0x03、0x06、0x10)
函数说明
读取保持寄存器:mb_read_reg_03(slave,addr,quantity)
- salve:从机站号
- addr:保存寄存器的起始地址
- quantity:读取的个数
读取成功,返回字数组;读取失败,返回nil
写单个保存寄存器:mb_write_reg_06 (slave,addr,reg)
- salve:从机站号
- addr:保存寄存器地址
- reg:寄存器值
写成功,返回ture;写失败,返回false;
写多个保存寄存器:mb_write_reg_16 (slave,addr,regs)
- salve:从机站号
- addr:写的起始地址
- regs:数组,word字数组
写成功,返回ture;写失败,返回false;
画面配置
通过mb函数来实现【保持寄存器】的读写,画面配置如下所示
读保存寄存器:
- 按钮控件ID1:作为读取“设置温度”、“设置湿度”的触发按钮,并将值显示在文本控件ID2、ID4中
- 文本控件ID2:显示mb_read_reg_03(,,,)获取变量“设置温度”的值
- 文本控件ID4:显示mb_read_reg_03(,,,)获取变量“设置湿度”的值
设置单个保存寄存器 “设置温度”:
- 按钮控件ID5:设置保存寄存器“设置温度” = 25 的触发按钮
设置多个线圈 “设置温度”、“设置湿度”:
- 按钮控件ID7:设置保存寄存器“设置温度” = 28、“设置湿度” = 60 的触发按钮
LUA脚本
按钮控件ID1按下时,将“设置温度”、“设置湿度”显示在文本控件ID2、文本控件ID4中,同理其他按钮/文本对应控件联动触发、显示,LUA脚本如下所示:
--用户通过触摸修改控件后,执行此回调函数。
--点击按钮控件,修改文本控件、修改滑动条都会触发此事件。
function on_control_notify(screen,control,value)
......
elseif screen == sc_holding
then
if control == 1 and value == 1
then
local holdTb = mb_read_reg_03(1, 0, 2)
if holdTb ~= nil
then
set_text(sc_holding, 2, holdTb[0])
set_text(sc_holding, 4, holdTb[1])
end
elseif control == 5 and value == 0
then
mb_write_reg_06(1, 0, 25)
elseif control == 7 and value == 0
then
local holdTb = {}
holdTb[0] = 28
holdTb[1] = 60
mb_write_reg_16(1, 0, holdTb)
end
......
end
end
运行效果
根据画面配置和LUA脚本,运行结果如下所示
14.5 输入寄存器(0x04)
函数说明
读输入寄存器:mb_read_input_reg_04(slave,addr,quantity)
- salve:从机站号
- addr:输入寄存器的起始地址
- quantity:读取的个数
读取成功,返回字数组;读取失败,返回nil
画面配置
通过mb函数来实现【输入寄存器】的读取,画面配置如下所示
读输入寄存器:
- 按钮控件ID1:作为读取输入寄存器“回风变量”、“回风湿度”的触发按钮,并将值显示在文本控件ID2、ID4中
- 文本控件ID2:显示mb_read_input_reg_04(,,,)获取变量“回风温度”的值
- 文本控件ID4:显示mb_read_input_reg_04(,,,)获取变量“回风湿度”的值
LUA脚本
按钮控件ID1按下时,将“回风温度”、“回风湿度”显示在文本控件ID2、文本控件ID4中,LUA脚本如下所示:
--用户通过触摸修改控件后,执行此回调函数。
--点击按钮控件,修改文本控件、修改滑动条都会触发此事件。
function on_control_notify(screen,control,value)
......
elseif screen == sc_input
then
if control == 1 and value == 1
then
local inputTb = mb_read_input_reg_04(1, 0, 2)
if inputTb ~= nil
then
set_text(sc_input, 2, inputTb[0])
set_text(sc_input, 4, inputTb[1])
end
end
......
end
运行预览
根据画面配置和LUA脚本,运行结果如下所示