跳到主要内容
版本:2.1

Modbus从站(Slave)

定义

命名空间:TouchSocketPro.Modbus
程序集:TouchSocketPro.Modbus.dll

一、说明

Modbus是主从通讯的。所以我们开发了Modbus服务器组件,方便大家使用。

二、特点

  • 简单易用。
  • 内存池支持
  • 高性能
  • 易扩展。
  • 支持全数据类型的读写

三、产品应用场景

  • 所有Modbus使用场景:可跨平台使用。

四、可配置项

无单独配置项。

五、支持插件

插件方法功能
IModbusSlaveExecutingPlugin当有主站请求读写该从站时触发。如果想要拒绝请求,可以通过e.IsPermitOperation = false执行。并且e.ErrorCode可以携带返回错误码。
IModbusSlaveExecutedPlugin当有主站完成请求读写该从站时触发

六、创建

目前TouchSokcet.Modbus从站支持TcpUdpRtuRtuOverTcpRtuOverUdp等协议。下面会一一介绍创建过程。

6.1 创建ModbusTcpSlave

var slave = new ModbusTcpSlave();
await slave.SetupAsync(new TouchSocketConfig()
//监听端口
.SetListenIPHosts(7808)
.ConfigurePlugins(a =>
{
a.AddModbusSlavePoint()//添加一个从站站点
.SetSlaveId(1)//设置站点号
//.UseIgnoreSlaveId()//忽略站号验证
.SetModbusDataLocater(new ModbusDataLocater(10, 10, 10, 10));//设置数据区
})
);
await slave.StartAsync();
Console.WriteLine("服务已启动");

6.2 创建ModbusUdpSlave

var slave = new ModbusUdpSlave();
await slave.SetupAsync(new TouchSocketConfig()
//监听端口
.SetBindIPHost(7809)
.ConfigurePlugins(a =>
{
a.Add<MyModbusSlavePlugin>();

a.AddModbusSlavePoint()//添加一个从站站点
.SetSlaveId(1)//设置站点号
.UseIgnoreSlaveId()//忽略站号验证
.SetModbusDataLocater(new ModbusDataLocater(10, 10, 10, 10));//设置数据区
})
);
await slave.StartAsync();
Console.WriteLine("服务已启动");

6.3 创建ModbusRtuSlave

var slave = new ModbusRtuSlave();
await slave.SetupAsync(new TouchSocketConfig()
//设置串口
.SetSerialPortOption(new SerialPortOption()
{
BaudRate = 9600,
DataBits = 8,
Parity = System.IO.Ports.Parity.Even,
PortName = "COM1",
StopBits = System.IO.Ports.StopBits.One
})
.ConfigurePlugins(a =>
{
a.Add<MyModbusSlavePlugin>();

a.AddModbusSlavePoint()//添加一个从站站点
.SetSlaveId(1)//设置站点号
//.UseIgnoreSlaveId()//如果不调用,默认会进行站号验证
.SetModbusDataLocater(new ModbusDataLocater(10, 10, 10, 10));//设置数据区
})
);

await slave.ConnectAsync();
Console.WriteLine("已连接COM端口");

6.4 创建ModbusRtuOverTcpSlave

var slave = new ModbusRtuOverTcpSlave();
await slave.SetupAsync(new TouchSocketConfig()
//监听端口
.SetListenIPHosts(7810)
.ConfigurePlugins(a =>
{
a.Add<MyModbusSlavePlugin>();

a.AddModbusSlavePoint()//添加一个从站站点
.SetSlaveId(1)//设置站点号
.UseIgnoreSlaveId()//忽略站号验证
.SetModbusDataLocater(new ModbusDataLocater(10, 10, 10, 10));//设置数据区
})
);
await slave.StartAsync();
Console.WriteLine("服务已启动");

6.5 创建ModbusRtuOverUdpSlave

var slave = new ModbusRtuOverUdpSlave();
await slave.SetupAsync(new TouchSocketConfig()
//监听端口
.SetBindIPHost(7811)
.ConfigurePlugins(a =>
{
a.Add<MyModbusSlavePlugin>();

a.AddModbusSlavePoint()//添加一个从站站点
.SetSlaveId(1)//设置站点号
.UseIgnoreSlaveId()//忽略站号验证
.SetModbusDataLocater(new ModbusDataLocater(10, 10, 10, 10));//设置数据区
})
);
await slave.StartAsync();
Console.WriteLine("服务已启动");

七、添加多个站点

Modbus是一主多从的架构。在实际使用时,一个ModbusSlave部署至一个机器(这里不考虑虚拟机),即视为一个从机。但事实上,按照Modbus协议,一个ModbusSlave可以有多个站点。以ModbusTcpSlave为例,他可以通过IP地址确定到唯一的设备,同时还可以通过SlaveId区分不同的站点。

所以,我们的ModbusSlave也可以有多个站点。以ModbusTcpSlave为例,具体操作如下:

static ModbusTcpSlave CreateModbusTcpSlave()
{
var service = new ModbusTcpSlave();
await service.SetupAsync(new TouchSocketConfig()
//监听端口
.SetListenIPHosts(7808)
.ConfigurePlugins(a =>
{
a.Add<MyModbusSlavePlugin>();

//当添加多个站点时,需要禁用IgnoreSlaveId的设定

a.AddModbusSlavePoint()//添加一个从站站点
.SetSlaveId(1)//设置站点号
//.UseIgnoreSlaveId()//忽略站号验证
.SetModbusDataLocater(new ModbusDataLocater(10,10,10,10));//设置数据区

a.AddModbusSlavePoint()//再添加一个从站站点
.SetSlaveId(2)//设置站点号
//.UseIgnoreSlaveId()//忽略站号验证
.SetModbusDataLocater(new ModbusDataLocater()//设置数据区
{
//下列配置表示,起始地址从1000开始,10个长度
Coils = new BooleanDataPartition(1000, 10),
DiscreteInputs = new BooleanDataPartition(1000, 10),
HoldingRegisters = new ShortDataPartition(1000, 10),
InputRegisters = new ShortDataPartition(1000, 10)
});
})
);
await service.StartAsync();
Console.WriteLine("服务已启动");
return service;
}
警告

当添加多个站点时,需要禁用IgnoreSlaveId的设定。

提示

所有的ModbusSlave均支持多站点访问。且多个站点还能共用同一个ModbusDataLocater

八、本地读写操作

所有的数据区均在IModbusSlavePoint中。所以需要先找到IModbusSlavePoint实例。

一般的,如果你使用了插件IModbusSlaveExecutingPlugin或者IModbusSlaveExecutedPlugin。插件的sender即为IModbusSlavePoint

如果你只能访问到IModbusSlave接口(例如:ModbusTcpSlave),那么你可以通过ModbusSlaveGetSlavePointBySlaveId方法获取到IModbusSlavePoint

var modbusSlavePoint= slave.GetSlavePointBySlaveId(slaveId: 1);

然后在IModbusSlavePoint接口中有ModbusDataLocater属性,该属性是Modbus数据存储区,即线圈离散输入保持寄存器输入寄存器

该属性是可读可写的。所以,即使是不同IModbusSlavePoint。也可以二次赋值,使其实现更多功能。

同时。可以通过该属性,创建一个本地ModbusMaster,用于直接读写。

具体读写操作和ModbusMaster读写一致。

var localMaster = modbusSlavePoint.ModbusDataLocater.CreateDataLocaterMaster();
var coils = localMaster.ReadCoils(0, 1);
提示

通过modbusSlavePoint.ModbusDataLocater.CreateDataLocaterMaster()创建的Master,具备ModbusMaster的所有功能(包括ModbusObject操作)。且是直接读取内存的,中间没有任何通信,所以速度非常快。

本文示例Demo