C#和NModbus库实现Modbus从站,支持自定义地址范围(如0-34)的寄存器配置
一、核心代码实现
csharp
using System;
using System.IO.Ports;
using NModbus;
using NModbus.Serial;
class ModbusRtuSlaveConfigurable
{
private static SerialPort _serialPort;
private static IModbusSlaveNetwork _slaveNetwork;
private static ushort _startAddress = 0; // 起始地址
private static ushort _endAddress = 34; // 结束地址(含)
static void Main(string[] args)
{
// 1. 配置串口参数
_serialPort = new SerialPort {
PortName = "COM3",
BaudRate = 9600,
Parity = Parity.None,
DataBits = 8,
StopBits = StopBits.One
};
// 2. 创建Modbus工厂和适配器
var factory = new ModbusFactory();
var adapter = new SerialPortAdapter(_serialPort);
// 3. 创建从站网络
_slaveNetwork = factory.CreateSlaveNetwork(adapter);
// 4. 创建从站实例(Slave ID=1)
var slave = factory.CreateSlave(unitId: 1);
// 5. 配置数据存储区(支持0x03读保持寄存器、0x01读线圈)
ConfigureDataStores(slave);
// 6. 启动监听
_slaveNetwork.AddSlave(slave);
_slaveNetwork.ListenAsync();
Console.WriteLine($"Modbus RTU从站已启动 (ID=1, 地址范围 {0}-{1}),按Enter退出...", _startAddress, _endAddress);
Console.ReadLine();
// 7. 清理资源
_serialPort.Close();
_slaveNetwork.Dispose();
}
static void ConfigureDataStores(IModbusSlave slave)
{
// 保持寄存器(地址0-34,共35个)
slave.DataStore.HoldingRegisters.StorageOperationOccurred += (sender, e) => {
Console.WriteLine($"[{DateTime.Now}] 寄存器 {e.StartingAddress} 被操作: {e.Operation}");
};
InitializeRegisters(slave.DataStore.HoldingRegisters);
// 线圈(地址0-34,共35个)
slave.DataStore.CoilDiscretes.StorageOperationOccurred += (sender, e) => {
Console.WriteLine($"[{DateTime.Now}] 线圈 {e.StartingAddress} 被操作: {e.Operation}");
};
InitializeCoils(slave.DataStore.CoilDiscretes);
}
static void InitializeRegisters(ISlaveDataStore<ushort> registers)
{
// 初始化保持寄存器默认值(示例:地址0=温度,地址1=压力)
registers[0] = 2500; // 温度值(单位:0.1℃)
registers[1] = 1200; // 压力值(单位:0.1kPa)
for (ushort i = 2; i <= _endAddress; i++) {
registers[i] = 0; // 其他寄存器初始化为0
}
}
static void InitializeCoils(ISlaveDataStore<bool> coils)
{
// 初始化线圈默认值(示例:地址0=设备运行状态)
coils[0] = true; // 设备运行中
for (ushort i = 1; i <= _endAddress; i++) {
coils[i] = false; // 其他线圈初始化为关闭
}
}
}
二、功能说明
1. 地址范围配置
- 修改起始/结束地址 :调整
_startAddress和_endAddress变量即可改变有效地址范围(如0-100) - 动态配置支持:可通过配置文件或命令行参数动态加载地址范围(见扩展部分)
2. 数据存储管理
| 存储类型 | 地址范围 | 数据类型 | 功能码 | 操作示例 |
|---|---|---|---|---|
| 保持寄存器 | 0x0000-0x0022 | 16位整数 | 0x03/0x06 | 读取温度值:03 03 00 00 00 01 |
| 离散输出(线圈) | 0x0000-0x0022 | 布尔值 | 0x01/0x05 | 写入运行状态:05 01 00 00 |
3. 事件监控
- 存储操作记录 :通过
StorageOperationOccurred事件实时记录数据变化 - 异常处理 :自动捕获无效地址访问并返回错误码(如
03 03 02 00 0A表示地址越界)
三、扩展功能实现
1. 动态地址配置(通过配置文件)
csharp
// app.config 添加配置项
<appSettings>
<add key="StartAddress" value="0"/>
<add key="EndAddress" value="34"/>
</appSettings>
// 读取配置
var startAddr = int.Parse(ConfigurationManager.AppSettings["StartAddress"]);
var endAddr = int.Parse(ConfigurationManager.AppSettings["EndAddress"]);
2. 自定义数据模拟
csharp
// 模拟温度传感器数据变化(每秒更新)
Timer timer = new Timer(_ => {
ushort temp = (ushort)(2000 + new Random().Next(100)); // 20.00~30.00℃
slave.DataStore.HoldingRegisters[0] = temp;
}, null, 0, 1000);
3. 安全校验增强
csharp
// 添加从站ID验证
if (request.UnitId != 1)
{
SendErrorResponse(request, 0x07); // 错误码07:从站ID不匹配
return;
}
四、扩展资源
- 参考代码:基于c#的modbus从站,可设定0134各个地址位 www.youwenfan.com/contentcsj/112185.html
- 调试工具:Modbus Poll(官方工具)、QModMaster(开源)
- 协议网页:Modbus RTU规范 modbus.org/docs/Modbus_RTU_Specification.pdf