CSoft.Protocol.Modbus
10.100.0
dotnet add package CSoft.Protocol.Modbus --version 10.100.0
NuGet\Install-Package CSoft.Protocol.Modbus -Version 10.100.0
<PackageReference Include="CSoft.Protocol.Modbus" Version="10.100.0" />
<PackageVersion Include="CSoft.Protocol.Modbus" Version="10.100.0" />
<PackageReference Include="CSoft.Protocol.Modbus" />
paket add CSoft.Protocol.Modbus --version 10.100.0
#r "nuget: CSoft.Protocol.Modbus, 10.100.0"
#:package CSoft.Protocol.Modbus@10.100.0
#addin nuget:?package=CSoft.Protocol.Modbus&version=10.100.0
#tool nuget:?package=CSoft.Protocol.Modbus&version=10.100.0
Modbus 协议库
一个简洁易用的 Modbus 通信库:主站 + 从站,Attribute 驱动的泛型数据映射、完整功能码支持、类型化异常。
- 主站 + 从站:
ModBusMaster发起读写,ModBusSlave应答请求,同一套[CHProtocol]模型 - 报文格式与物理传输解耦:RTU / TCP 报文可跑在串口、TCP、命名管道任一传输上
- 泛型映射:
[CHProtocol]标注模型属性,一行代码读写整个数据块 - 功能码齐全:FC01 / 02 / 03 / 04 / 05 / 06 / 15 / 16
- 快速分帧:按帧长驱动解析,帧完整即处理,无静默等待;噪声与残留自动恢复
- 现场友好:四种字序(ABCD / DCBA / BADC / CDAB)、字符串编码可配
- 现代 API:类型化异常、
CancellationToken、自动拆包与合并
安装
dotnet add package CSoft.Protocol.Modbus
快速开始
1. 定义数据模型
public class SensorData
{
[CHProtocol(1)] // 寄存器地址 1(float 占 1、2 两个寄存器)
public float Temperature { get; set; }
[CHProtocol(3)]
public ushort Humidity { get; set; }
[CHProtocol(5)]
public float Pressure { get; set; }
[CHProtocol(7, count: 4)] // string 必须声明寄存器个数(4 寄存器 = 8 字节)
public string DeviceName { get; set; } = string.Empty;
[CHProtocol(11)] // bool 映射为单寄存器 0 / 1
public bool Running { get; set; }
}
2. 建立连接
Builder 方式(推荐):
// 串口 + RTU(默认)
var master = ModBusMaster.UseSerial("COM2", baudRate: 9600).Build();
await master.OpenAsync();
// 网络 + TCP 报文格式
var master = ModBusMaster.UseTcp("192.168.1.100", 502)
.Protocol(ModbusType.TCP)
.Timeout(3000) // 可选:请求超时(毫秒)
.Build();
构造函数方式:
using Communication.Bus.PhysicalPort;
var master = new ModBusMaster(new TcpClient("192.168.1.100", 502), ModbusType.TCP);
await master.OpenAsync();
ModbusType指的是报文格式,与物理链路无关:串口上可以跑 TCP 报文,网络上也可以跑 RTU 报文,按设备实际协议选择即可。
3. 读写数据
byte address = 0x01;
// 读:自动按地址合并相邻寄存器,通常一次请求拿回全部字段
var data = await master.GetAsync<SensorData>(address);
Console.WriteLine($"{data.Temperature}, {data.Humidity}, {data.DeviceName}");
// 写:连续地址的字段自动合并为一帧
await master.SetAsync(address, new SensorData
{
Temperature = 25.5f,
Humidity = 60,
DeviceName = "PUMP-A",
Running = true
});
地址支持字符串形式:"1"、"01"、"0x01" 均可。
功能码 API
除泛型模型外,也提供寄存器 / 线圈的原始读写:
| 方法 | 功能码 | 说明 |
|---|---|---|
ReadHoldingRegistersAsync(addr, start, count) |
FC03 | 读保持寄存器,返回 ushort[] |
ReadInputRegistersAsync(addr, start, count) |
FC04 | 读输入寄存器,返回 ushort[] |
ReadCoilsAsync(addr, start, count) |
FC01 | 读线圈,返回 bool[] |
ReadDiscreteInputsAsync(addr, start, count) |
FC02 | 读离散量输入,返回 bool[] |
WriteRegisterAsync(addr, register, value) |
FC06 | 写单个寄存器 |
WriteCoilAsync(addr, coil, value) |
FC05 | 写单个线圈 |
WriteRegistersAsync(addr, start, values) |
FC16 | 写多个寄存器 |
WriteCoilsAsync(addr, start, values) |
FC15 | 写多个线圈 |
var regs = await master.ReadHoldingRegistersAsync(0x01, start: 100, count: 10);
var coils = await master.ReadCoilsAsync(0x01, start: 0, count: 16);
await master.WriteRegisterAsync(0x01, register: 0x0064, value: 123);
await master.WriteCoilsAsync(0x01, start: 0, values: [true, false, true]);
超出单帧上限(读 125 / 写 123 个寄存器,读 2000 / 写 1968 个线圈)时自动拆分成多帧。
支持的数据类型
| C# 类型 | 寄存器数 | 说明 |
|---|---|---|
ushort / short |
1 | |
uint / int / float |
2 | 字序可配 |
double |
4 | 字序可配 |
bool |
1 | 0 / 1 |
string |
N | 必须 [CHProtocol(..., count: N)] |
字节序
多寄存器数值(float / int32 / double)的字节排列按设备现场情况选择,默认 ABCD(Modbus 标准大端):
master.ReqWordOrder = WordOrder.CDAB; // 请求方向:交换 16 位字(常见于国产仪表的 float)
master.RspWordOrder = WordOrder.CDAB; // 响应方向
| WordOrder | 线上字节(值 0x12345678) | 常见场景 |
|---|---|---|
ABCD |
12 34 56 78 |
标准 Modbus |
DCBA |
78 56 34 12 |
小端设备 |
CDAB |
56 78 12 34 |
字交换,float 最常见 |
BADC |
34 12 78 56 |
字节交换 |
单个属性也可用 [CHProtocol] 通道级覆盖(Channel.IsHighByteBefore)。
字符串编码
master.StringEncoding = Encoding.GetEncoding("GB2312"); // 默认 ASCII
写入时不足 count * 2 字节自动补 0x00;读取时自动截断尾部 \0。
异常处理
所有通信错误抛出 Modbus.Exceptions 下的类型化异常:
using Modbus.Exceptions;
try
{
var data = await master.GetAsync<SensorData>(0x01);
}
catch (ModbusSlaveException ex) // 从站返回异常响应
{
Console.WriteLine($"异常码 {ex.ExceptionCode},地址 0x{ex.DeviceAddress:X2}");
// ex.ExceptionCode: IllegalFunction / IllegalDataAddress / IllegalDataValue ...
}
catch (ModbusCrcException) // RTU CRC 校验失败
{
}
catch (ModbusFrameException) // 帧结构非法:事务 ID / 地址 / 功能码 / 字节数不符
{
}
catch (ModbusTimeoutException) // 超时未收到有效响应
{
}
通信语义与健壮性
解析按帧长驱动:RTU 由功能码 + 字节数域推导帧长,TCP 由 MBAP 长度域确定,帧一完整即处理,不存在静默等待;帧长无法推导时按 CRC 校验滑窗判定。每帧进入数据映射前经过完整校验链:
CRC / MBAP → 从站地址 → 功能码 → 字节数 / 写回显 → 通道边界
任何一环不符都抛类型化异常——错误停在异常层,脏数据永远进不了模型。
常见异常现场的恢复行为:
| 情况 | 行为 |
|---|---|
| 线路噪声、上次残留的尾巴 | 不成帧的残字节随下一帧一起跳过,缓冲自动对齐 |
| 从站矮帧(字节数域虚高、数据少发) | CRC 滑窗识别出真实帧长,立刻报结构错误,不等超时 |
| 从站无响应 / 响应损坏 | 请求超时抛 ModbusTimeoutException,重试即可,不影响后续 |
| 纯噪声持续灌入(错波特率等) | 缓冲 4096 字节封顶,整段丢弃垃圾,不会无限增长 |
设计原则:任何单次异常只影响当次请求,不污染后续通信。
从机(ModBusSlave)
ModBusSlave 维护四个数据区(保持寄存器 / 输入寄存器 / 线圈 / 离散量输入),
应答主站的 FC01/02/03/04/05/06/15/16 请求,越界 / 非法值 / 未知功能码自动回异常响应,
支持 RTU 地址过滤与广播(地址 0 只执行写、不响应)。
建立从站
// 点对点(串口等)
var slave = new ModBusSlave(new SerialPort("COM3"), new ModBusSlaveOptions
{
Address = 0x01,
HoldingRegisterCount = 100,
CoilCount = 64
});
await slave.StartAsync();
// TCP 服务端(多客户端,响应自动发回请求来源客户端)
var server = Comm.TopServer()
.UseTcpServer("0.0.0.0", 502)
.WithParserFactory(ModBusSlave.CreateParser)
.Build();
var tcpSlave = new ModBusSlave(server, new ModBusSlaveOptions { Address = 0x01, ModbusType = ModbusType.TCP });
await tcpSlave.StartAsync();
数据区与事件
slave.HoldingRegisters[0] = 0x1234; // 直接读写元素
slave.Coils[5] = true;
slave.WriteReceived += e => // 主站写入(含广播)后的回调
{
Console.WriteLine($"主站写入 FC{e.FunctionCode:X2} 起始 {e.StartAddress}");
};
模型绑定
与主站共用同一个 [CHProtocol] 模型:绑定后主站读到的就是模型的值,主站写入自动同步回模型:
var model = new SensorData { Temperature = 25.5f, DeviceName = "PUMP-A" };
slave.BindModel(model); // 模型 → 保持寄存器
model.Temperature = 30f;
slave.SyncModelToRegisters(); // 设备逻辑改模型后发布,主站即可读到
无传输核心
HandleRequest 与传输无关,一帧进一帧出(null 表示不响应),可直接用于测试或自定义传输:
var slave = new ModBusSlave(new ModBusSlaveOptions { Address = 0x01 });
byte[]? response = slave.HandleRequest(masterRequestFrame);
高级用法
手动构建 BlockList
var blockList = BlockList.From<SensorData>();
blockList.MaxMergeGap = 2; // 允许 2 个寄存器的缺口合并,减少往返
var channels = await master.GetAsync(0x01, blockList);
master.MaxMergeGap 对泛型读取同样生效(默认 0,仅合并完全连续的块)。
取消令牌
所有读写方法均接受 CancellationToken:
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));
var data = await master.GetAsync<SensorData>(0x01, cts.Token);
事件与状态
ModBusMaster 实现 IProtocol,具备 OpenAsync / CloseAsync / IsConnect 以及
OnConnect / OnDisconnect / OnSentData / OnReceivedData 事件。
配置项
| 属性 | 默认值 | 说明 |
|---|---|---|
ModbusType |
RTU |
报文格式:RTU / TCP |
ReqWordOrder / RspWordOrder |
ABCD |
多寄存器数值字序 |
IsHighByteBefore_Req / _Rsp |
true |
旧版字节序开关(映射到 WordOrder) |
IsHighByteBefore_MBAP |
true |
MBAP 字段字节序(标准为大端) |
StringEncoding |
ASCII | string 通道编码 |
MaxMergeGap |
0 | 读块合并允许的寄存器缺口 |
BlockInfos |
空 | 无参 GetAsync(address) 使用的块定义 |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- CSoft.Protocol (>= 10.6.2)
-
net10.0
- CSoft.Protocol (>= 10.6.2)
-
net8.0
- CSoft.Protocol (>= 10.6.2)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.14)
-
net9.0
- CSoft.Protocol (>= 10.6.2)
- Microsoft.Bcl.AsyncInterfaces (>= 10.0.14)
NuGet packages (6)
Showing the top 5 NuGet packages that depend on CSoft.Protocol.Modbus:
| Package | Downloads |
|---|---|
|
CSoft.Protocol.TPF146D
泽天温压流146D通讯协议 |
|
|
CSoft.Protocol.DustAnalyzerSampling
泽天抽取粉尘仪通讯协议 |
|
|
CSoft.Protocol.TPF113B
泽天温压流113B通讯协议 |
|
|
CSoft.Protocol.DustAnalyzerSquare
泽天方型粉尘仪通讯协议 |
|
|
CSoft.Protocol.DustAnalyzerCircular
泽天圆型粉尘仪通讯协议 |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 10.100.0 | 50 | 10/29/2026 | |
| 10.2.1 | 223 | 8/21/2026 | |
| 10.2.0 | 167 | 5/28/2026 | |
| 10.1.1 | 148 | 5/19/2026 | |
| 10.1.0 | 149 | 5/11/2026 | |
| 10.0.10 | 160 | 3/31/2026 | |
| 10.0.9 | 153 | 3/30/2026 | |
| 10.0.8 | 291 | 1/14/2026 | |
| 10.0.7 | 228 | 1/14/2026 | |
| 10.0.6 | 227 | 1/13/2026 | |
| 10.0.5 | 217 | 1/13/2026 | |
| 10.0.4 | 223 | 1/13/2026 | |
| 10.0.3 | 228 | 1/9/2026 | |
| 10.0.2 | 244 | 1/8/2026 | |
| 10.0.1 | 197 | 1/8/2026 | |
| 10.0.0 | 414 | 11/12/2025 | |
| 9.3.2 | 386 | 8/5/2025 | |
| 9.3.1 | 399 | 7/29/2025 | |
| 9.3.0 | 683 | 7/24/2025 | |
| 9.2.5 | 1,083 | 7/23/2025 |
添加从机