基于C#實現(xiàn)Modbus RTU通信
一、環(huán)境配置與依賴安裝
# NuGet包安裝(支持.NET Framework 4.5+) Install-Package NModbus4 Install-Package System.IO.Ports
二、核心代碼實現(xiàn)
1. 串口初始化與連接
using System.IO.Ports;
using Modbus.Device;
public class ModbusRtuMaster
{
private SerialPort _serialPort;
private IModbusSerialMaster _master;
public void Connect(string portName, int baudRate = 9600, Parity parity = Parity.None,
int dataBits = 8, StopBits stopBits = StopBits.One)
{
try
{
_serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits)
{
ReadTimeout = 3000,
WriteTimeout = 3000
};
_serialPort.Open();
_master = ModbusSerialMaster.CreateRtu(_serialPort);
_master.Transport.Retries = 3; // 設置重試次數(shù)
_master.Transport.WriteTimeout = 2000;
_master.Transport.ReadTimeout = 2000;
}
catch (Exception ex)
{
Console.WriteLine($"連接失敗: {ex.Message}");
throw;
}
}
public void Disconnect()
{
_master?.Close();
_serialPort?.Close();
}
}
2. 數(shù)據(jù)讀取操作
public ushort[] ReadHoldingRegisters(byte slaveId, ushort startAddr, ushort count)
{
try
{
return _master.ReadHoldingRegisters(slaveId, startAddr, count);
}
catch (ModbusException ex)
{
Console.WriteLine($"Modbus錯誤: {ex.ErrorCode}");
return null;
}
catch (IOException ex)
{
Console.WriteLine($"通信異常: {ex.Message}");
return null;
}
}
// 示例調(diào)用
var data = master.ReadHoldingRegisters(1, 0, 10); // 從站1讀取保持寄存器0-9
3. 數(shù)據(jù)寫入操作
public void WriteSingleRegister(byte slaveId, ushort address, ushort value)
{
_master.WriteSingleRegister(slaveId, address, value);
}
public void WriteMultipleCoils(byte slaveId, ushort startAddr, bool[] values)
{
_master.WriteMultipleCoils(slaveId, startAddr, values);
}
三、關鍵功能實現(xiàn)
1. CRC16校驗(Modbus標準)
public static class Crc16
{
public static byte[] Compute(byte[] data)
{
ushort crc = 0xFFFF;
foreach (byte b in data)
{
crc ^= (ushort)b;
for (int i = 0; i < 8; i++)
{
if ((crc & 0x0001) != 0)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return new[] { (byte)crc, (byte)(crc >> 8) };
}
public static bool Validate(byte[] dataWithCrc)
{
if (dataWithCrc.Length < 2) return false;
byte[] data = dataWithCrc.Take(dataWithCrc.Length - 2).ToArray();
byte[] crc = Compute(data);
return crc[0] == dataWithCrc[dataWithCrc.Length - 2]
&& crc[1] == dataWithCrc[dataWithCrc.Length - 1];
}
}
2. 幀間延遲計算
private int CalculateInterFrameDelay()
{
int charBits = 1 + _serialPort.DataBits +
(_serialPort.StopBits == StopBits.One ? 1 : 2) +
(_serialPort.Parity == Parity.None ? 0 : 1);
return (int)(3500.0 * charBits / _serialPort.BaudRate); // 3.5字符時間
}
四、錯誤處理與調(diào)試
1. 異常處理策略
try
{
var data = ReadHoldingRegisters(1, 0, 10);
if (data == null) throw new InvalidOperationException("讀取失敗");
}
catch (TimeoutException)
{
Console.WriteLine("通信超時,請檢查設備狀態(tài)");
Reconnect();
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"操作失敗: {ex.Message}");
}
2. 自動重連機制
private void Reconnect()
{
Disconnect();
Thread.Sleep(1000);
Connect(_config.PortName, _config.BaudRate);
}
五、性能優(yōu)化
1批量操作優(yōu)化
// 批量讀取多個寄存器區(qū)域
public Dictionary<ushort, ushort[]> BatchRead(
params (byte SlaveId, ushort StartAddr, ushort Count)[] requests)
{
var results = new Dictionary<ushort, ushort[]>();
Parallel.ForEach(requests, request =>
{
var data = ReadHoldingRegisters(request.SlaveId, request.StartAddr, request.Count);
lock (results) results[request.SlaveId] = data;
});
return results;
}
2異步通信實現(xiàn)
public async Task<ushort[]> ReadAsync(byte slaveId, ushort startAddr, ushort count)
{
return await Task.Run(() => ReadHoldingRegisters(slaveId, startAddr, count));
}
參考代碼 C#利用modbus rtu模式與下位機通訊 www.youwenfan.com/contentcsr/112701.html
六、完整項目結構
ModbusRTUDemo/
├── src/
│ ├── ModbusMaster/ // 主站核心邏輯
│ ├── SerialPortConfig.cs // 串口配置管理
│ └── ProtocolHandler.cs // 協(xié)議解析器
├── tests/
│ ├── ModbusTests.cs // 單元測試
│ └── StressTests.cs // 壓力測試
└── docs/
└── 開發(fā)指南.md
七、調(diào)試與測試工具
虛擬串口工具
使用VSPD創(chuàng)建虛擬串口對(如COM3<->COM4),方便調(diào)試
Wireshark抓包分析
過濾
Modbus RTU協(xié)議,觀察完整的請求/響應幀結構Modbus從站模擬
使用Modbus Slave工具創(chuàng)建測試從站設備
八、擴展應用場景
1.多從站管理
public class ModbusNetwork
{
private Dictionary<byte, ModbusRtuMaster> _slaves = new();
public void AddSlave(byte address, string portName)
{
var master = new ModbusRtuMaster();
master.Connect(portName);
_slaves[address] = master;
}
}
2.數(shù)據(jù)緩存機制
public class DataCache
{
private Dictionary<ushort, (DateTime Timestamp, ushort Value)[]> _cache = new();
public void UpdateCache(ushort[] data, ushort startAddr)
{
_cache[startAddr] = data.Select((v, i) =>
(DateTime.Now, v)).ToArray();
}
}
九、最佳實踐建議
參數(shù)配置規(guī)范
- 波特率:9600/19200/115200(根據(jù)設備手冊選擇)
- 數(shù)據(jù)格式:8N1(默認配置)
- 超時時間:讀操作1000ms,寫操作500ms
安全防護措施
- 添加設備認證機制
- 實現(xiàn)數(shù)據(jù)加密傳輸
- 設置訪問權限控制
到此這篇關于基于C#實現(xiàn)Modbus RTU通信的文章就介紹到這了,更多相關C# Modbus RTU通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C# WinForm實現(xiàn)自動更新程序之客戶端的示例代碼
這篇文章主要為大家詳細介紹了利用C# WinForm實現(xiàn)自動更新程序之客戶端的實現(xiàn)方法,文中的示例代碼講解詳細,感興趣的小伙伴可以嘗試一下2022-10-10
C#?CefSharp?根據(jù)輸入日期段自動選擇日期的操作代碼
這篇文章主要介紹了C#?CefSharp?根據(jù)輸入日期段自動選擇日期的操作代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01

