Files
Sleep-Multi-functionality/SerialPortHelper/ModbusHelper.cs
2026-05-04 14:46:58 +08:00

106 lines
3.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}