mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-20 02:16:42 +08:00
在多个 `.mdx` 文件中添加对 `TouchSocketCoreDefinition`、`TouchSocketHttpDefinition`、`TouchSocketDmtpDefinition`、`TouchSocketModbusDefinition`、`TouchSocketProModbusDefinition`、`TouchSocketNamedPipeDefinition`、`TouchSocketWebApiDefinition`、`TouchSocketJsonRpcDefinition` 和 `TouchSocketXmlRpcDefinition` 的导入。增加解析和处理定义部分的 JavaScript 脚本,确保导入的有效性和一致性。新增功能包括精确匹配定义部分的正则表达式、解析定义内容的函数、生成定义组件的函数、递归查找 `.mdx` 文件的功能,以及验证导入的有效性
247 lines
7.8 KiB
Plaintext
247 lines
7.8 KiB
Plaintext
---
|
||
id: modbusslave
|
||
title: Modbus从站(Slave)
|
||
---
|
||
|
||
import Tag from "@site/src/components/Tag.js";
|
||
import Pro from "@site/src/components/Pro.js";
|
||
import { TouchSocketProModbusDefinition } from "@site/src/components/Definition.js";
|
||
|
||
### 定义
|
||
|
||
<TouchSocketProModbusDefinition />
|
||
|
||
|
||
## 一、说明 <Pro/>
|
||
|
||
Modbus是主从通讯的。所以我们开发了Modbus服务器组件,方便大家使用。
|
||
|
||
|
||
## 二、特点
|
||
|
||
- 简单易用。
|
||
- 内存池支持
|
||
- 高性能
|
||
- 易扩展。
|
||
- **支持全数据类型的读写**。
|
||
|
||
## 三、产品应用场景
|
||
|
||
- 所有Modbus使用场景:可跨平台使用。
|
||
|
||
## 四、可配置项
|
||
|
||
无单独配置项。
|
||
|
||
## 五、支持插件
|
||
|
||
| 插件方法| 功能 |
|
||
| --- | --- |
|
||
| IModbusSlaveExecutingPlugin | 当有主站请求读写该从站时触发。如果想要拒绝请求,可以通过e.IsPermitOperation = false执行。并且e.ErrorCode可以携带返回错误码。|
|
||
| IModbusSlaveExecutedPlugin | 当有主站完成请求读写该从站时触发 |
|
||
|
||
## 六、创建
|
||
|
||
目前`TouchSokcet.Modbus`从站支持`Tcp`、`Udp`、`Rtu`、`RtuOverTcp`、`RtuOverUdp`等协议。下面会一一介绍创建过程。
|
||
|
||
#### 6.1 创建ModbusTcpSlave
|
||
|
||
```csharp showLineNumbers
|
||
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
|
||
|
||
```csharp showLineNumbers
|
||
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
|
||
|
||
```csharp showLineNumbers
|
||
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
|
||
|
||
```csharp showLineNumbers
|
||
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
|
||
|
||
```csharp showLineNumbers
|
||
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`为例,具体操作如下:
|
||
|
||
```csharp {18-28} showLineNumbers
|
||
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;
|
||
}
|
||
```
|
||
|
||
:::caution 警告
|
||
|
||
当添加多个站点时,需要**禁用**`IgnoreSlaveId`的设定。
|
||
|
||
:::
|
||
|
||
:::tip 提示
|
||
|
||
所有的`ModbusSlave`均支持多站点访问。且多个站点还能共用同一个`ModbusDataLocater`。
|
||
|
||
:::
|
||
|
||
## 八、本地读写操作
|
||
|
||
所有的数据区均在`IModbusSlavePoint`中。所以需要先找到`IModbusSlavePoint`实例。
|
||
|
||
一般的,如果你使用了插件`IModbusSlaveExecutingPlugin`或者`IModbusSlaveExecutedPlugin`。插件的sender即为`IModbusSlavePoint`。
|
||
|
||
如果你只能访问到`IModbusSlave`接口(例如:`ModbusTcpSlave`),那么你可以通过`ModbusSlave`的`GetSlavePointBySlaveId`方法获取到`IModbusSlavePoint`。
|
||
|
||
```csharp showLineNumbers
|
||
var modbusSlavePoint= slave.GetSlavePointBySlaveId(slaveId: 1);
|
||
```
|
||
|
||
然后在`IModbusSlavePoint`接口中有`ModbusDataLocater`属性,该属性是`Modbus`数据存储区,即`线圈`、`离散输入`、`保持寄存器`、`输入寄存器`。
|
||
|
||
该属性是可读可写的。所以,即使是不同`IModbusSlavePoint`。也可以二次赋值,使其实现更多功能。
|
||
|
||
同时。可以通过该属性,创建一个本地`ModbusMaster`,用于直接读写。
|
||
|
||
具体读写操作和[ModbusMaster读写](./modbusmaster.mdx)一致。
|
||
|
||
```csharp showLineNumbers
|
||
var localMaster = modbusSlavePoint.ModbusDataLocater.CreateDataLocaterMaster();
|
||
var coils = localMaster.ReadCoils(0, 1);
|
||
```
|
||
|
||
:::tip 提示
|
||
|
||
通过`modbusSlavePoint.ModbusDataLocater.CreateDataLocaterMaster()`创建的Master,具备[ModbusMaster](./modbusmaster.mdx)的所有功能(包括`ModbusObject`操作)。且是直接读取内存的,中间没有任何通信,所以速度非常快。
|
||
|
||
:::
|
||
|
||
|
||
[本文示例Demo](https://gitee.com/RRQM_Home/TouchSocket/tree/master/examples/Modbus/ModbusSlaveConsoleApp)
|
||
|