以下是关于在C#中使用NModbus4库进行Modbus通信的完整技术指南,包含代码示例和工程实践:
一、开发环境搭建
Install-Package NModbus4
<Form>
<ComboBox Name="cmbPort" Items="COM1,COM2,COM3"/>
<Button Name="btnConnect" Text="连接"/>
<Button Name="btnRead" Text="读取寄存器"/>
<TextBox Name="txtLog" Multiline="true" ScrollBars="Vertical"/>
</Form>
二、Modbus RTU主站实现
private SerialPort _serialPort;
private IModbusSerialMaster _master;
private void ConnectRTU()
{
_serialPort = new SerialPort(cmbPort.Text, 9600, Parity.None, 8, StopBits.One)
{
ReadTimeout = 1000,
WriteTimeout = 1000
};
_serialPort.Open();
_master = ModbusSerialMaster.CreateRtu(_serialPort);
_master.Transport.Retries = 3; // 设置重试次数
}
public ushort[] ReadHoldingRegisters(byte slaveId, ushort startAddr, ushort count)
{
try
{
return _master.ReadHoldingRegisters(slaveId, startAddr, count);
}
catch (Exception ex)
{
Log($"读取失败: {ex.Message}");
return null;
}
}
06功能码(写单个寄存器)
public void WriteSingleRegister(byte slaveId, ushort address, ushort value)
{
_master.WriteSingleRegister(slaveId, address, value);
}
三、Modbus TCP主站实现
private TcpClient _tcpClient;
private IModbusMaster _tcpMaster;
private void ConnectTCP()
{
_tcpClient = new TcpClient("192.168.1.100", 502);
_tcpMaster = ModbusIpMaster.CreateIp(_tcpClient);
}
// 读取输入寄存器(04功能码)
ushort[] inputs = _tcpMaster.ReadInputRegisters(1, 0, 10);
// 批量写线圈(15功能码)
bool[] coils = { true, false, true };
_tcpMaster.WriteMultipleCoils(1, 0, coils);
四、高级功能实现
private System.Timers.Timer _pollTimer;
void StartPolling()
{
_pollTimer = new System.Timers.Timer(1000);
_pollTimer.Elapsed += (s,e) =>
{
var data = ReadHoldingRegisters(1, 0, 10);
UpdateUI(data);
};
_pollTimer.Start();
}
Task.Run(() =>
{
using (var master = ModbusSerialMaster.CreateRtu(_serialPort))
{
while (true)
{
// 异步读取操作
var values = master.ReadHoldingRegisters(1, 0, 10);
ProcessData(values);
}
}
});
五、从站实现方案
private ModbusSlave _slave;
void StartRtuSlave()
{
_serialPort = new SerialPort("COM2", 9600);
var factory = new ModbusFactory();
_slave = factory.CreateRtuSlave(1, new DataStore());
_slave.Listen(_serialPort.BaseStream);
}
public class DataStore : IModbusDataStore
{
private readonly Dictionary<ushort, ushort> _registers = new();
public ushort[] ReadRegisters(ushort start, ushort count)
{
return Enumerable.Range(start, count)
.Select(addr => _registers.GetValueOrDefault(addr))
.ToArray();
}
}
六、调试与测试
// 启用调试日志
_master.Transport.LoggingEnabled = true;
_master.Transport.Log += (s,e) =>
Debug.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] {e.Message}");
七、最佳实践
参数配置建议
波特率:9600/19200/115200
超时时间:读1000ms,写500ms
重试次数:3次
错误处理机制
try
{
// 业务代码
}
catch (ModbusException ex)
{
Log($"Modbus错误: {ex.ErrorCode}");
}
catch (IOException ex)
{
Log($"IO异常: {ex.Message}");
Reconnect();
}