Files

106 lines
3.3 KiB
C#
Raw Permalink Normal View History

2026-05-04 14:46:58 +08:00
public static class ModbusHelper
{
// 生成写单个线圈(功能码05)的Modbus指令
public static string GenerateWriteSingleCoilCommand(byte deviceAddress, ushort coilAddress, bool value)
{
byte[] command = new byte[6];
command[0] = deviceAddress;
command[1] = 0x05; // 写单个线圈功能码
command[2] = (byte)(coilAddress >> 8);
command[3] = (byte)coilAddress;
command[4] = value ? (byte)0xFF : (byte)0x00;
command[5] = 0x00;
// 计算CRC校验
ushort crc = CalculateCRC(command, 6);
byte[] crcBytes = BitConverter.GetBytes(crc);
// 组合完整命令(包含CRC校验)
byte[] fullCommand = new byte[8];
Array.Copy(command, fullCommand, 6);
fullCommand[6] = crcBytes[0]; // CRC低字节在前
fullCommand[7] = crcBytes[1]; // CRC高字节在后
// 转换为十六进制字符串
return BitConverter.ToString(fullCommand).Replace("-", "");
}
// 验证Modbus响应是否有效
public static bool ValidateResponse(string command, string response)
{
if (string.IsNullOrEmpty(response) || response.Length < 8)
return false;
// 解析响应字符串为字节数组
byte[] responseBytes = StringToByteArray(response);
// 从原始命令中提取设备地址
byte deviceAddress = StringToByteArray(command.Substring(0, 2))[0];
// 验证设备地址
if (responseBytes[0] != deviceAddress)
return false;
// 验证功能码(响应中的功能码应与请求相同若有异常则功能码最高位为1)
byte requestFunctionCode = StringToByteArray(command.Substring(2, 2))[0];
byte responseFunctionCode = responseBytes[1];
// 检查是否为异常响应
if ((responseFunctionCode & 0x80) != 0)
{
byte errorCode = responseBytes[2];
Console.WriteLine($"Modbus异常响应 - 功能码: {requestFunctionCode}, 错误码: {errorCode}");
return false;
}
// 验证功能码是否匹配
if (responseFunctionCode != requestFunctionCode)
return false;
// 验证CRC校验
ushort receivedCrc = (ushort)((responseBytes[responseBytes.Length - 2] << 8) | responseBytes[responseBytes.Length - 1]);
ushort calculatedCrc = CalculateCRC(responseBytes, responseBytes.Length - 2);
return receivedCrc == calculatedCrc;
}
// 计算Modbus RTU CRC校验
private static ushort CalculateCRC(byte[] data, int length)
{
ushort crc = 0xFFFF;
for (int i = 0; i < length; i++)
{
crc ^= data[i];
for (int j = 0; j < 8; j++)
{
if ((crc & 0x0001) != 0)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
// 将十六进制字符串转换为字节数组
private static byte[] StringToByteArray(string hex)
{
int length = hex.Length;
byte[] bytes = new byte[length / 2];
for (int i = 0; i < length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
}