功能强大的Modbus从站模拟器使用说明
本模拟器是一个 Modbus 从站应用程序,可提供模拟多个从站。您可以用它在从供应商处收到实际的从站设备之前,即可开始编程和测试。
下载地址:https://www.redisant.cn/mse
- 支持多种Modbus协议,包括:
- Modbus RTU
- Modbus ASCII
- Modbus TCP/IP
- Modbus UDP/IP
- Modbus RTU Over TCP/IP
- Modbus RTU Over UDP/IP
- 支持按照业务类型对寄存器进行分组管理。
- 支持自定义C#脚本,动态返回数据。
- 监视串行线路或以太网上的通信数据。
- 支持多达 28 种数据格式,包括:Signed、Unsigned、Hex、Binary、Long、Float、Double、String等。
- 支持 Modbus 协议地址和 PLC 地址相互切换。
- 对任意数量寄存器中的数据绘制实时图表,监控数据的变化趋势。
- 支持同时创建多个连接网络和大量从站设备。
- 通过多个标签页进行管理,快速在从站设备之间进行切换。
- 通过表格的形式管理寄存器,支持添加变量名和注释,支持切换背景与前景颜色。
- 导出/导入从站设备寄存器数据到Excel。
- 内置字节转换工具,方便将Long、Float、Double类型数据转换为寄存器中的数据。
- 内置数据校验工具,支持 CRC、LRC 校验。
- 通过缓动函数模拟寄存器值的变化,带来更真实的数据仿真体验。
- 支持丰富的 Modbus 功能码:
- 01 (0x01) 读取线圈
- 02 (0x02) 读取离散输入
- 03 (0x03) 读取保持寄存器
- 04 (0x04) 读取输入寄存器
- 05 (0x05) 写单个线圈
- 06 (0x06) 写单个寄存器
- 08 (0x08) 诊断(仅限串口)
- 11 (0x0B) 获取通讯事件计数器(仅限串口)
- 15 (0x0F) 写入多个线圈
- 16 (0x10) 写入多个寄存器
- 17 (0x11) 报告服务器 ID(仅限串口)
- 22 (0x16) 掩码写入寄存器
- 23 (0x17) 读/写多个寄存器
- 43 / 14 (0x2B / 0x0E) 读取设备标识
在 Windows 上,安装本软件非常简单,双击安装程序,并选择合适的安装目录,创建桌面快捷方式,之后,程序便会正确安装在你的电脑上。
要在macOS上安装,下载最新的.dmg包,双击打开安装程序,将软件拖动到下方的程序目录即可。如果在安装时出错或者在运行软件时出错,请继续阅读下面的处理方式:
- 安装时报错
如果在安装时报错:“已损坏,无法打开。 您应该将推出磁盘映像”。因为当前版本未进行签名,被 GateKeeper 机制拦截。通过以下步骤来暂时关闭 GateKeeper(安装后再打开) :
\begin{enumerate}
- 在“系统偏好设置” -> “安全与隐私” 中选择 “任何来源”; 如果您的系统没有此选项,在终端中执行以下命令后再次打开此设置页,然后勾选“任何来源”,参考图:
sudo spctl --master-disable
- 之后再双击安装软件即可。
- (可选)安装完成之后,您可以还原之前的设置,这会保护您的Mac免受恶意软件的骚扰,通过以下命令打开 GateKeeper:sudo spctl --master-enable
- 运行时报错
如果在运行时报错:“已损坏,无法打开。 您应该将它移到废纸篓”。是因为当前版本未进行签名,被Mac GateKeeper机制拦截;打开终端输入以下命令来解除对本软件的隔离:
$ sudo xattr -rd com.apple.quarantine /Applications/Modbus\ Slave\ Emulator.app
如果提示没有 -r 选项,检查调用的命令是否正确:
$ which -a xattr
/Library/Frameworks/Python.framework/Versions/3.11/bin/xattr
/usr/bin/xattr
确保使用第二个命令
$ sudo /usr/bin/xattr -rd com.apple.quarantine /Applications/Modbus\ Slave\ Emulator.app
下载最新的压缩包,然后执行以下步骤:
- 解压压缩包:
$ tar -zxvf ModbusSlaveEmulator-1.0.0.0-linux-x64.tar.gz
- 设置语言环境(或略此步骤可能导致软件启动报错):
$ export LANG=en_US.UTF-8
- 为文件添加可执行权限:
$ chmod +x ./ModbusSlaveEmulator-1.0.0.0-linux-x64/ModbusSlaveEmulator
- 最后运行程序:
./ModbusSlaveEmulator-1.0.0.0-linux-x64/ModbusSlaveEmulator
注意,请将版本号(上文中的1.0.0.0)替换为你实际下载的版本号。
第一步是创建连接,选择“新建连接”,在新建连接窗口中,可以配置要使用规约类型。共有五种不同的连接方式:
- 串口:通过串口线(RS232 或 RS485)进行 Modbus 通信。可以使用 USB 串口转换器。
- Modbus TCP/IP:如果需要与 Modbus TCP/IP 网络通信,请选择 TCP/IP。在这种情况下,从站 ID 与 Modbus TCP/IP 中使用的设备 ID 相同。默认端口号为 502。
- Modbus UDP/IP:如果需要与 Modbus UDP/IP 网络通信,请选择 UDP/IP。它与 Modbus TCP/IP 类似,但使用无连接的 UDP 协议。
- Modbus RTU over TCP/IP:通过 TCP/IP 网络而非串口线发送 RTU 消息。
- Modbus RTU over UDP/IP:通过 UDP/IP 网络而非串口线发送 RTU 消息。
这些参数用于配置串口设置,仅当连接类型为“串口”时可用。
- 串口号:当前系统已存在的物理或虚拟串口号
- 波特率:串口波特率,通信双方必须一致
- 数据位:通信过程中传输的有效数据位数,数据位通常有5、6、7 、8
- 奇偶校验位
- 停止位
- 流控
- 消息模式:使用此选项选择 RTU 或 ASCII 模式。默认值为 RTU。
- IP 地址:指定要监听的 IP 地址。默认值为 127.0.0.1。
- 端口号:指定要监听的端口号。默认值为 502。
注意:服务器IP地址是指本模拟器绑定的本机地址,使用127.0.0.1或者本机的其他IP地址。要查看本机的IP地址,启动控制台,然后使用 ipconfig 命令:
PS C:\Users\Alice> ipconfig
无线局域网适配器 WLAN:
连接特定的 DNS 后缀 . . . . . . . :
IPv4 地址 . . . . . . . . . . . . : 192.168.31.166
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.31.1
你可以在模拟器中添加多个modbus从站。每个从站将独立工作。也可以删除从站。创建完连接之后,选中创建的连接,然后点击“创建从站”,在“创建从站”窗口中,可以配置从站别名,从站ID,并配置寄存器组。
点击加号或减号,可以添加或删除寄存器组。在每个组中,可以配置组名、寄存器的类型、寄存器的起始地址和数量。创建完成后,点击确定,即可创建从站。
- 从站 ID:范围从1 至 255。
- 响应延迟:响应主站每个请求前的延迟毫秒数。默认值为 0 毫秒。
- 使用随机值初始化寄存器:如果设置为 true,寄存器将使用随机值进行初始化。默认值为 false。
- 地址类型:Modbus 协议地址(基数 0),PLC 地址(基数 1)
- 配置寄存器组:您可以一次添加多个寄存器组;唯一的要求是组内寄存器地址不能重叠。
- 组名称:设置寄存器组的名称。
- 寄存器类型,您可以选择以下四种类型之一:
- 01:线圈 (0x),可读写
- 02:离散输入 (1x),只读
- 03:保持寄存器 (4x),可读写
- 04:输入寄存器 (3x),只读
- 起始地址:组中第一个寄存器的地址。
- 数量:该组寄存器的总数。
对于创建好的从站,你可以导出从站的所有寄存器组,具体操作为,在从站上右击,在弹出菜单中选择“导出从站数据”,即可将本从站的所有寄存器组导入到Excel文件。在导出的Excel文件中,您可以编辑变量名、寄存器值,新建或删除寄存器组,然后重新导入到软件,操作为,在从站上右击,在弹出菜单中选择“导入从站数据”,这是在软件中手动创建寄存器组的另一替代方式。
创建完从站之后,双击组名即可打开该寄存器组
- 在变量名列,通过双击单元格即可编辑变量名。
- 在寄存器值列,通过选中一行或多行(Ctrl+鼠标左键),在下方编辑寄存器值。
- 在右击的弹出菜单中,可以配置寄存器值的编码格式,数组自动变化。
对于寄存器组中寄存器地址的格式,软件支持以十六进制或十进制显示。在从站上右击,在弹出菜单中选择寄存器地址的显示格式。
Modbus从站模拟器支持多种编码格式:
- 16 位有符号整数
- 16 位无符号整数
- 十六进制字节数组
- 二进制位串
- 32 位有符号整数
- 32 位无符号整数
- 32 位浮点数
- 64 位双精度浮点数
- 最常用编码的字符串
通过选择一个或多个寄存器,您可以方便的编辑这些值。
- 当选中单个寄存器时(表格中的一行),Unsigned-Signed-Hex-Binary标签页和String标签页可用,在Unsigned-Signed-Hex-Binary标签页中,将单个寄存器解释为有符号十六进制数、无符号十六进制数、原始的2字节十六进制数组、16位的位串。选中任何一个输入框,即可编辑该类型的值。String标签页同理,您可以直接输入字符串,软件将自动寄存器的值。
- 当选中连续的两个寄存器,Long标签页和Float标签页可用,两个寄存器的组合将被解释为32位有符号数或者32位浮点数。
- 当选中连续的两个寄存器,Double标签页可用,四个寄存器的组合将被解释为64位浮点数。
选择一行或多行寄存器,然后从右键菜单中选择实时图表选项。共有五种图表选项:
- 作为 unsigned 绘制
- 作为 signed 绘制
- 作为 long 绘制
- 作为 float 绘制
- 作为 double 绘制
选中连接,然后点击“通信细节”,这里我们可以监控Modbus通信的报文,
在Modbus Slave Emulator中,可以使用自定义C#脚本。选中从站,右击,在弹出菜单中选择“编辑脚本”。编写脚本时,你需要实现下面这个抽象类,当主站(客户端)发起读写寄存器请求时,执行脚本中对应的方法。
namespace ModbusSlaveEmulator.Script
{
public abstract class DefaultHandler
{
// 下面四种数组,代表了用户在UI上配置的每种类型的寄存器
// 从站配置了多个就访问多少,数组索引不要超限
// 比如,配置保持寄存器,起始地址10 (base 0),数量为100
// 那么应该使用HoldingRegisters[10],HoldingRegisters[11],...,HoldingRegisters[109]
public ModbusSlaveEmulator.Script.ReadOnlyArray<bool> Coils; //线圈状态
public ModbusSlaveEmulator.Script.ReadOnlyArray<bool> DiscreteInputs; //离散输入状态
public ModbusSlaveEmulator.Script.ReadOnlyArray<ushort> HoldingRegisters; //保持寄存器
public ModbusSlaveEmulator.Script.ReadOnlyArray<ushort> InputRegisters; //输入寄存器
/// <summary>
/// 读线圈状态
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="numberOfPoints">读取的数量</param>
/// <returns>返回的数组长度应该为numberOfPoints</returns>
public virtual bool[] ReadCoils(ushort startAddress, ushort numberOfPoints)
{
return null;
}
/// <summary>
/// 写线圈状态
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="points">要写入的数据</param>
public virtual void WriteCoils(ushort startAddress, bool[] points)
{
}
/// <summary>
/// 读离散输入状态
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="numberOfPoints">读取的数量</param>
/// <returns>返回的数组长度应该为numberOfPoints</returns>
public virtual bool[] ReadDiscreteInputs(ushort startAddress, ushort numberOfPoints)
{
return null;
}
/// <summary>
/// 读保持寄存器
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="numberOfPoints">读取的数量</param>
/// <returns>返回的数组长度应该为numberOfPoints</returns>
public virtual ushort[] ReadHoldingRegisters(ushort startAddress, ushort numberOfPoints)
{
return null;
}
/// <summary>
/// 写保持寄存器
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="points">要写入的数据</param>
public virtual void WriteHoldingRegisters(ushort startAddress, ushort[] points)
{
}
/// <summary>
/// 读输入寄存器
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="numberOfPoints">读取的数量</param>
/// <returns>返回的数组长度应该为numberOfPoints</returns>
public virtual ushort[] ReadInputRegisters(ushort startAddress, ushort numberOfPoints)
{
return null;
}
}
}
下面是一个实现上面接口的例子,注意:DefaultHandler的实现类必须命名为Handler:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.ObjectModel;
/// <summary>
/// ModbusSlaveEmulator.Script.DefaultHandler 实现示例
/// </summary>
public class Handler : ModbusSlaveEmulator.Script.DefaultHandler
{
/// <summary>
/// 读线圈状态
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="numberOfPoints">读取的数量</param>
/// <returns>返回的数组长度应该为numberOfPoints</returns>
public override bool[] ReadCoils(ushort startAddress, ushort numberOfPoints)
{
bool[] array = new bool[numberOfPoints];
for (int i = 0; i < array.Length; i++)
{
if (i % 2 == 0)
{
//返回在UI表格里配置的数据值,并取反
array[i] = !Coils[startAddress + i];
}
else
{
array[i] = false;
}
}
return array;
}
/// <summary>
/// 写线圈状态
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="points">要写入的数据</param>
public override void WriteCoils(ushort startAddress, bool[] points)
{
//ignore
}
/// <summary>
/// 读离散输入状态
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="numberOfPoints">读取的数量</param>
/// <returns>返回的数组长度应该为numberOfPoints</returns>
public override bool[] ReadDiscreteInputs(ushort startAddress, ushort numberOfPoints)
{
bool[] array = new bool[numberOfPoints];
for (int i = 0; i < array.Length; i++)
{
array[i] = true;
}
return array;
}
/// <summary>
/// 读保持寄存器
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="numberOfPoints">读取的数量</param>
/// <returns>返回的数组长度应该为numberOfPoints</returns>
public override ushort[] ReadHoldingRegisters(ushort startAddress, ushort numberOfPoints)
{
ushort[] array = new ushort[numberOfPoints];
for (int i = 0; i < array.Length; i++)
{
//返回在UI表格里配置的数据值,并+3
array[i] = (ushort) (HoldingRegisters[startAddress + i] + 3);
}
return array;
}
/// <summary>
/// 写保持寄存器
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="points">要写入的数据</param>
public override void WriteHoldingRegisters(ushort startAddress, ushort[] points)
{
//ignore
}
/// <summary>
/// 读输入寄存器
/// </summary>
/// <param name="startAddress">寄存器起始地址(Protocol Address Base 0)</param>
/// <param name="numberOfPoints">读取的数量</param>
/// <returns>返回的数组长度应该为numberOfPoints</returns>
public override ushort[] ReadInputRegisters(ushort startAddress, ushort numberOfPoints)
{
ushort[] array = new ushort[numberOfPoints];
for (int i = 0; i < array.Length; i++)
{
//返回在UI表格里配置的数据值,并+1
array[i] = (ushort) (InputRegisters[startAddress + i] + 1);
}
return array;
}
}















浙公网安备 33010602011771号