更新
This commit is contained in:
@@ -657,51 +657,191 @@ namespace COFTester.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 將兩個寄存器轉換為 Float (IEEE 754 Big-Endian)
|
/// 將兩個寄存器轉換為 32位浮點型 (IEEE 754)
|
||||||
/// Modbus 標準字節序:高字在前,每字內高字節在前
|
///
|
||||||
|
/// Modbus 寄存器格式:
|
||||||
|
/// - 每個寄存器 16位 (2字節)
|
||||||
|
/// - 兩個寄存器組成 32位浮點數
|
||||||
|
///
|
||||||
|
/// 字節序處理(小端交換):
|
||||||
|
/// - PLC 發送:[Reg0_High, Reg0_Low, Reg1_High, Reg1_Low]
|
||||||
|
/// - 小端系統需要:[Reg1_Low, Reg1_High, Reg0_Low, Reg0_High]
|
||||||
|
///
|
||||||
|
/// 生產環境驗證:確保與 PLC 浮點數格式完全匹配
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected float ConvertRegistersToFloat(ushort[] registers, int startIndex = 0)
|
/// <param name="registers">Modbus 寄存器數組</param>
|
||||||
|
/// <param name="startIndex">起始索引(默認0)</param>
|
||||||
|
/// <returns>32位浮點數</returns>
|
||||||
|
public enum FloatByteOrder
|
||||||
{
|
{
|
||||||
|
ABCD, // 标准Modbus: 寄存器0=高16位,寄存器1=低16位,大端序
|
||||||
|
CDAB, // 反转Modbus: 寄存器0=低16位,寄存器1=高16位,大端序
|
||||||
|
BADC, // 小端序格式(较少见)
|
||||||
|
DCBA // 完全反转(最少见)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected float ConvertRegistersToFloat(ushort[] registers, int startIndex = 0,
|
||||||
|
FloatByteOrder byteOrder = FloatByteOrder.BADC)
|
||||||
|
{
|
||||||
|
// 参数校验
|
||||||
|
if (registers == null)
|
||||||
|
throw new ArgumentNullException(nameof(registers), "寄存器数组不能为空");
|
||||||
|
|
||||||
if (registers.Length < startIndex + 2)
|
if (registers.Length < startIndex + 2)
|
||||||
throw new ArgumentException("寄存器數組長度不足");
|
throw new ArgumentException($"寄存器数组长度不足:需要至少 {startIndex + 2} 个,实际 {registers.Length} 个");
|
||||||
|
|
||||||
ushort highReg = registers[startIndex];
|
// 读取寄存器值
|
||||||
ushort lowReg = registers[startIndex + 1];
|
ushort reg0 = registers[startIndex];
|
||||||
|
ushort reg1 = registers[startIndex + 1];
|
||||||
|
|
||||||
byte[] floatBytes = new byte[4];
|
// 创建字节数组
|
||||||
// 高寄存器→高2字節,低寄存器→低2字節
|
Span<byte> floatBytes = stackalloc byte[4]; // 使用 Span 提升性能并减少堆分配
|
||||||
floatBytes[0] = (byte)(highReg >> 8);
|
|
||||||
floatBytes[1] = (byte)highReg;
|
|
||||||
floatBytes[2] = (byte)(lowReg >> 8);
|
|
||||||
floatBytes[3] = (byte)lowReg;
|
|
||||||
|
|
||||||
// 處理小端序系統
|
// 根据字节序填充字节数组
|
||||||
if (BitConverter.IsLittleEndian)
|
switch (byteOrder)
|
||||||
{
|
{
|
||||||
Array.Reverse(floatBytes);
|
case FloatByteOrder.ABCD: // 标准Modbus大端序
|
||||||
|
floatBytes[0] = (byte)(reg0 >> 8); // A
|
||||||
|
floatBytes[1] = (byte)(reg0 & 0xFF); // B
|
||||||
|
floatBytes[2] = (byte)(reg1 >> 8); // C
|
||||||
|
floatBytes[3] = (byte)(reg1 & 0xFF); // D
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FloatByteOrder.CDAB: // 反转Modbus
|
||||||
|
floatBytes[0] = (byte)(reg1 & 0xFF); // D
|
||||||
|
floatBytes[1] = (byte)(reg1 >> 8); // C
|
||||||
|
floatBytes[2] = (byte)(reg0 & 0xFF); // B
|
||||||
|
floatBytes[3] = (byte)(reg0 >> 8); // A
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FloatByteOrder.BADC: // 小端序格式
|
||||||
|
floatBytes[0] = (byte)(reg0 & 0xFF); // B
|
||||||
|
floatBytes[1] = (byte)(reg0 >> 8); // A
|
||||||
|
floatBytes[2] = (byte)(reg1 & 0xFF); // D
|
||||||
|
floatBytes[3] = (byte)(reg1 >> 8); // C
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FloatByteOrder.DCBA: // 完全反转
|
||||||
|
floatBytes[0] = (byte)(reg1 >> 8); // C
|
||||||
|
floatBytes[1] = (byte)(reg1 & 0xFF); // D
|
||||||
|
floatBytes[2] = (byte)(reg0 >> 8); // A
|
||||||
|
floatBytes[3] = (byte)(reg0 & 0xFF); // B
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException($"未知的字节顺序:{byteOrder}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return BitConverter.ToSingle(floatBytes, 0);
|
// 转换为浮点数
|
||||||
|
float result = BitConverter.ToSingle(floatBytes.ToArray(), 0);
|
||||||
|
|
||||||
|
// 调试信息
|
||||||
|
System.Diagnostics.Debug.WriteLine(
|
||||||
|
$"[Modbus] Float转换: Order={byteOrder}, " +
|
||||||
|
$"Reg0=0x{reg0:X4}, Reg1=0x{reg1:X4}, " +
|
||||||
|
$"Result={result:G9}"
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 將 Float 轉換為兩個寄存器 (IEEE 754 Big-Endian)
|
/// 將 32位浮點型轉換為兩個寄存器 (IEEE 754)
|
||||||
|
///
|
||||||
/// 與 ConvertRegistersToFloat 保持對稱的字節順序處理
|
/// 與 ConvertRegistersToFloat 保持對稱的字節順序處理
|
||||||
|
/// 默認使用 CDAB 字節序(與讀取方法一致)
|
||||||
|
///
|
||||||
|
/// 字節序處理:
|
||||||
|
/// - 小端系統:BitConverter.GetBytes 產生 [Byte0(LSB), Byte1, Byte2, Byte3(MSB)]
|
||||||
|
/// - CDAB 格式:Reg0=低16位(CD),Reg1=高16位(AB)
|
||||||
|
/// - 映射關係:Byte0,Byte1→Reg0, Byte2,Byte3→Reg1
|
||||||
|
///
|
||||||
|
/// 生產環境驗證:確保與 PLC 浮點數格式完全匹配
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ushort[] ConvertFloatToRegisters(float value)
|
/// <param name="value">32位浮點數</param>
|
||||||
|
/// <param name="byteOrder">字節序(默認 CDAB,與讀取方法一致)</param>
|
||||||
|
/// <returns>兩個 Modbus 寄存器</returns>
|
||||||
|
protected ushort[] ConvertFloatToRegisters(float value, FloatByteOrder byteOrder = FloatByteOrder.CDAB)
|
||||||
{
|
{
|
||||||
|
// 將浮點數轉換為字節數組
|
||||||
byte[] bytes = BitConverter.GetBytes(value);
|
byte[] bytes = BitConverter.GetBytes(value);
|
||||||
|
|
||||||
// 處理小端序系統:先轉為大端序
|
// 參數驗證
|
||||||
|
if (bytes == null || bytes.Length != 4)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"浮點數字節長度異常:期望 4,實際 {bytes?.Length ?? 0}");
|
||||||
|
|
||||||
|
// 分配寄存器數組
|
||||||
|
ushort[] registers = new ushort[2];
|
||||||
|
|
||||||
|
// BitConverter.GetBytes 在小端系統上產生: [Byte0(LSB), Byte1, Byte2, Byte3(MSB)]
|
||||||
|
// 需要根據目標字節序重新組裝
|
||||||
if (BitConverter.IsLittleEndian)
|
if (BitConverter.IsLittleEndian)
|
||||||
{
|
{
|
||||||
Array.Reverse(bytes);
|
switch (byteOrder)
|
||||||
|
{
|
||||||
|
case FloatByteOrder.ABCD:
|
||||||
|
// 标准Modbus大端序: Reg0=高16位(AB),Reg1=低16位(CD)
|
||||||
|
// 小端字节: [D,C,B,A] → Reg0=AB, Reg1=CD
|
||||||
|
registers[0] = (ushort)((bytes[3] << 8) | bytes[2]); // A,B
|
||||||
|
registers[1] = (ushort)((bytes[1] << 8) | bytes[0]); // C,D
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FloatByteOrder.CDAB:
|
||||||
|
// 字交换: Reg0=低16位(CD),Reg1=高16位(AB)
|
||||||
|
// 小端字节: [D,C,B,A] → Reg0=CD, Reg1=AB
|
||||||
|
registers[0] = (ushort)((bytes[1] << 8) | bytes[0]); // C,D
|
||||||
|
registers[1] = (ushort)((bytes[3] << 8) | bytes[2]); // A,B
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FloatByteOrder.BADC:
|
||||||
|
// 字节交换: Reg0=BA,Reg1=DC
|
||||||
|
// 小端字节: [D,C,B,A] → Reg0=BA, Reg1=DC
|
||||||
|
registers[0] = (ushort)((bytes[2] << 8) | bytes[3]); // B,A
|
||||||
|
registers[1] = (ushort)((bytes[0] << 8) | bytes[1]); // D,C
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FloatByteOrder.DCBA:
|
||||||
|
// 完全反转: Reg0=DC,Reg1=BA
|
||||||
|
// 小端字节: [D,C,B,A] → Reg0=DC, Reg1=BA
|
||||||
|
registers[0] = (ushort)((bytes[0] << 8) | bytes[1]); // D,C
|
||||||
|
registers[1] = (ushort)((bytes[2] << 8) | bytes[3]); // B,A
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 大端系统(罕见)
|
||||||
|
switch (byteOrder)
|
||||||
|
{
|
||||||
|
case FloatByteOrder.ABCD:
|
||||||
|
registers[0] = (ushort)((bytes[0] << 8) | bytes[1]);
|
||||||
|
registers[1] = (ushort)((bytes[2] << 8) | bytes[3]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FloatByteOrder.CDAB:
|
||||||
|
registers[0] = (ushort)((bytes[2] << 8) | bytes[3]);
|
||||||
|
registers[1] = (ushort)((bytes[0] << 8) | bytes[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FloatByteOrder.BADC:
|
||||||
|
registers[0] = (ushort)((bytes[1] << 8) | bytes[0]);
|
||||||
|
registers[1] = (ushort)((bytes[3] << 8) | bytes[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FloatByteOrder.DCBA:
|
||||||
|
registers[0] = (ushort)((bytes[3] << 8) | bytes[2]);
|
||||||
|
registers[1] = (ushort)((bytes[1] << 8) | bytes[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ushort[] registers = new ushort[2];
|
// 調試輸出(生產環境可保留用於故障排查)
|
||||||
// Big-Endian 字序:高字在前
|
System.Diagnostics.Debug.WriteLine(
|
||||||
registers[0] = (ushort)((bytes[0] << 8) | bytes[1]);
|
$"[Modbus] Float寫入: Float={value:F3} " +
|
||||||
registers[1] = (ushort)((bytes[2] << 8) | bytes[3]);
|
$"→ Bytes=[{bytes[0]:X2},{bytes[1]:X2},{bytes[2]:X2},{bytes[3]:X2}] " +
|
||||||
|
$"→ Reg[0]=0x{registers[0]:X4}, Reg[1]=0x{registers[1]:X4} (字節序:{byteOrder})"
|
||||||
|
);
|
||||||
|
|
||||||
return registers;
|
return registers;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user