基于C#和NModbus4庫實現的Modbus RTU串口通信,包含完整的界面設計和功能實現:
一、項目依賴配置
-
NuGet包安裝:
Install-Package NModbus4 Install-Package System.IO.Ports
-
窗體控件布局:
<!-- 基礎控件配置 --> <ComboBox x:Name="cmbPort" Margin="5" Width="120"/> <Button x:Name="btnConnect" Content="連接" Margin="5"/> <Button x:Name="btnRead" Content="讀取寄存器" Margin="5"/> <TextBox x:Name="txtLog" Height="200" Margin="5" TextWrapping="Wrap"/> <DataGrid x:Name="dgData" AutoGenerateColumns="False" Margin="5"><DataGrid.Columns><DataGridTextColumn Header="地址" Binding="{Binding Address}"/><DataGridTextColumn Header="值" Binding="{Binding Value}"/></DataGrid.Columns> </DataGrid>
二、核心代碼實現
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Windows;
using Modbus.Device;namespace ModbusRTUDemo
{public partial class MainWindow : Window{#region 成員變量private IModbusSerialMaster _master;private SerialPort _serialPort;private const ushort START_ADDR = 40001; // 起始寄存器地址private const ushort READ_COUNT = 10; // 讀取數量#endregionpublic MainWindow(){InitializeComponent();InitializeSerialPorts();btnConnect.Click += BtnConnect_Click;btnRead.Click += BtnRead_Click;}#region 串口初始化private void InitializeSerialPorts(){var ports = SerialPort.GetPortNames();cmbPort.ItemsSource = ports;cmbPort.SelectedIndex = 0;}#endregion#region 連接控制private void BtnConnect_Click(object sender, RoutedEventArgs e){try{if (_master != null && _master.IsOpen){Disconnect();btnConnect.Content = "連接";txtLog.AppendText("已斷開連接\n");return;}_serialPort = new SerialPort(cmbPort.Text, 9600, Parity.None, 8, StopBits.One){ReadTimeout = 3000,WriteTimeout = 3000};_master = ModbusSerialMaster.CreateRtu(_serialPort);_master.Transport.Retries = 3; // 重試次數_master.Transport.WriteTimeout = 2000;_master.Transport.ReadTimeout = 2000;_master.Open();btnConnect.Content = "斷開";txtLog.AppendText($"已連接到 {_serialPort.PortName}\n");}catch (Exception ex){txtLog.AppendText($"連接失敗: {ex.Message}\n");}}#endregion#region 數據讀取private async void BtnRead_Click(object sender, RoutedEventArgs e){try{var result = await Task.Run(() => _master.ReadHoldingRegisters(1, START_ADDR, READ_COUNT));dgData.ItemsSource = result.Select((value, index) => new {Address = START_ADDR + index,Value = value.ToString("0.00")}).ToList();txtLog.AppendText($"讀取成功: {result.Length} 個寄存器\n");}catch (Exception ex){txtLog.AppendText($"讀取失敗: {ex.Message}\n");}}#endregion#region 連接管理private void Disconnect(){_master?.Close();_master = null;_serialPort?.Close();}protected override void OnClosed(EventArgs e){base.OnClosed(e);Disconnect();}#endregion}
}
參考代碼 C# 寫的串口通信程序源碼 youwenfan.com/contentcsb/111840.html
三、關鍵功能說明
- 串口配置
- 支持自動檢測可用串口(通過
SerialPort.GetPortNames()
) - 默認參數:9600波特率、無校驗、8數據位、1停止位
- 支持自動檢測可用串口(通過
- Modbus操作
- 讀取保持寄存器:
ReadHoldingRegisters
方法實現 - 寫單個寄存器:擴展方法
WriteSingleRegister
- 批量寫線圈:
WriteMultipleCoils
方法
- 讀取保持寄存器:
- 異常處理
- 自動重試機制(默認3次重試)
- 超時設置(讀寫各2秒)
四、擴展功能實現
-
定時數據采集
private System.Timers.Timer _pollTimer = new System.Timers.Timer(5000);private void StartPolling() {_pollTimer.Elapsed += (s,e) => {var data = _master.ReadHoldingRegisters(1, START_ADDR, READ_COUNT);Dispatcher.Invoke(() => UpdateDataGrid(data));};_pollTimer.Start(); }
-
CRC校驗實現
private byte[] CalculateCRC(byte[] data) {ushort crc = 0xFFFF;for (int i = 0; i < data.Length; i++){crc ^= (ushort)data[i];for (int j = 0; j < 8; j++){if ((crc & 0x0001) != 0){crc >>= 1;crc ^= 0xA001;}else{crc >>= 1;}}}return new byte[] { (byte)crc, (byte)(crc >> 8) }; }
五、調試技巧
-
串口監控
使用虛擬串口工具(如VSPD)進行通信調試 -
數據驗證
// 校驗從站響應 if (response.SlaveId != slaveId) throw new InvalidDataException("從站ID不匹配");
-
協議分析
通過Wireshark抓包分析Modbus RTU幀結構
完整項目源碼可通過NuGet部署NModbus4庫后導入Visual Studio運行。實際應用中需根據設備手冊調整功能碼和寄存器地址。