基于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运行。实际应用中需根据设备手册调整功能码和寄存器地址。