提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、 不使用库
写单个寄存器
public void SendModbusData(SerialPort serialPort, byte deviceAddress, ushort registerAddress, ushort registerValue)
{
byte[] modbusFrame = new byte[8];
modbusFrame[0] = deviceAddress; // 设备地址
modbusFrame[1] = 0x06; // 功能码 (写单个寄存器)
modbusFrame[2] = (byte)(registerAddress >> 8); // 寄存器地址高字节
modbusFrame[3] = (byte)(registerAddress & 0xFF); // 寄存器地址低字节
modbusFrame[4] = (byte)(registerValue >> 8); // 寄存器值高字节
modbusFrame[5] = (byte)(registerValue & 0xFF); // 寄存器值低字节
// 计算CRC
ushort crc = CalculateCRC(modbusFrame, 6);
modbusFrame[6] = (byte)(crc & 0xFF); // CRC低字节
modbusFrame[7] = (byte)(crc >> 8); // CRC高字节
// 发送数据
if (serialPort.IsOpen)
{
serialPort.Write(modbusFrame, 0, modbusFrame.Length);
}
else
{
throw new InvalidOperationException("串口未打开");
}
}
数据校验
private ushort CalculateCRC(byte[] data, int length)
{
ushort crc = 0xFFFF;
for (int pos = 0; pos < length; pos++)
{
crc ^= (ushort)data[pos];
for (int i = 8; i != 0; i--)
{
if ((crc & 0x0001) != 0)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
读取单个寄存器
public void SendModbusQuery(SerialPort serialPort, byte deviceAddress, ushort registerAddress)
{
byte[] modbusFrame = new byte[8];
modbusFrame[0] = deviceAddress; // 设备地址
modbusFrame[1] = 0x03; // 功能码 (读取单个寄存器)
modbusFrame[2] = (byte)(registerAddress >> 8); // 寄存器地址高字节
modbusFrame[3] = (byte)(registerAddress & 0xFF); // 寄存器地址低字节
modbusFrame[4] = 0x00; // 读取一个寄存器,寄存器数目高字节
modbusFrame[5] = 0x01; // 读取一个寄存器,寄存器数目低字节
// 计算CRC
ushort crc = CalculateCRC(modbusFrame, 6);
modbusFrame[6] = (byte)(crc & 0xFF); // CRC低字节
modbusFrame[7] = (byte)(crc >> 8); // CRC高字节
// 发送数据
if (serialPort.IsOpen)
{
serialPort.Write(modbusFrame, 0, modbusFrame.Length);
}
else
{
throw new InvalidOperationException("串口未打开");
}
}
二、使用NModbu库
首先,你需要安装 NModbus 库。可以通过NuGet包管理器来安装:
1. 引入必要的命名空间
代码如下(示例):
using System;
using System.IO.Ports;
using NModbus;
using NModbus.Serial;
2.初始化串口和MODBUS主站:
代码如下(示例):
class Program
{
static void Main(string[] args)
{
// 配置串口参数
string portName = "COM3"; // 串口号
int baudRate = 9600; // 波特率
Parity parity = Parity.None; // 校验位
int dataBits = 8; // 数据位
StopBits stopBits = StopBits.One; // 停止位
// 创建串口对象
using (SerialPort serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits))
{
// 打开串口
serialPort.Open();
// 创建MODBUS主站
IModbusSerialMaster master = new ModbusSerialMaster(serialPort, ModbusSerialTransportMode.Rtu);
// 设置超时时间
master.Transport.ReadTimeout = 500;
master.Transport.WriteTimeout = 500;
// 发送请求并接收响应
SendAndReceive(master);
}
}
3.发送和接收请求:
static void SendAndReceive(IModbusSerialMaster master)
{
try
{
// 目标设备地址
byte slaveId = 0x01;
// 读取保持寄存器
ushort startAddress = 0x0001; // 起始地址
ushort numberOfPoints = 2; // 读取的寄存器数量
// 发送读保持寄存器请求
ushort[] registers = master.ReadHoldingRegisters(slaveId, startAddress, numberOfPoints);
// 输出读取的寄存器值
Console.WriteLine("Read Holding Registers:");
for (int i = 0; i < registers.Length; i++)
{
Console.WriteLine($"Register {startAddress + i}: {registers[i]}");
}
// 写单个保持寄存器
ushort writeAddress = 0x0001; // 要写入的寄存器地址
ushort writeValue = 0x0001; // 要写入的值
// 发送写单个保持寄存器请求
master.WriteSingleRegister(slaveId, writeAddress, writeValue);
Console.WriteLine($"Wrote value {writeValue} to register {writeAddress}");
// 广播复位命令
byte broadcastAddress = 0x00;
ushort resetAddress = 0x0000; // 要写入的寄存器地址
ushort resetValue = 0x0001; // 要写入的值
// 发送广播复位命令
master.WriteSingleRegister(broadcastAddress, resetAddress, resetValue);
Console.WriteLine($"Broadcast reset command sent to all devices");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}