1. 按ushort多字节写入
NModbus 写寄存器API:
public void WriteSingleRegister(byte slaveAddress, ushort registerAddress, ushort value)
{
WriteSingleRegisterRequestResponse message = new WriteSingleRegisterRequestResponse(slaveAddress, registerAddress, value);
base.Transport.UnicastMessage<WriteSingleRegisterRequestResponse>(message);
}
public void WriteMultipleRegisters(byte slaveAddress, ushort startAddress, ushort[] data)
{
ValidateData("data", data, 123);
WriteMultipleRegistersRequest message = new WriteMultipleRegistersRequest(slaveAddress, startAddress, new RegisterCollection(data));
base.Transport.UnicastMessage<WriteMultipleRegistersResponse>(message);
}
根据不同的设备信号解析类型,大致可以分为:
/// <summary>
/// 浮点数解析字节序格式
/// </summary>
public enum ParseFormat
{
/// <summary>
/// 标准32位:字节顺序 1 2 3 4 = AB CD
/// </summary>
ABCD,
/// <summary>
/// 字节反转:BA DC
/// </summary>
BADC,
/// <summary>
/// 高低字交换:CD AB
/// </summary>
CDAB,
/// <summary>
/// 完全反转:DC BA
/// </summary>
DCBA
}
1.1 float 类型写入
这里主要是把一个 float 转换为对应的 ushort[].
/// <summary>
/// 将 float 按照指定字节序转换为两个 ushort
/// </summary>
/// <param name="value">float值</param>
/// <param name="parseFormat">解析格式ABCD/BADC/CDAB/DCBA</param>
/// <returns>[高16位, 低16位]</returns>
private static ushort[] ConvertFloatToTwoUShorts(float value, ParseFormat parseFormat)
{
byte[] bytes = BitConverter.GetBytes(value);
ushort[] result = new ushort[2];
switch (parseFormat)
{
case ParseFormat.ABCD:
// 标准:AB CD
result[0] = BitConverter.ToUInt16(bytes, 2);
result[1] = BitConverter.ToUInt16(bytes, 0);
break;
case ParseFormat.BADC:
// 低16位内部反转:BA CD
result[0] = BitConverter.ToUInt16(bytes, 2);
result[1] = ReverseUShort(BitConverter.ToUInt16(bytes, 0));
break;
case ParseFormat.CDAB:
// 高低16位互换:CD AB
result[0] = BitConverter.ToUInt16(bytes, 0);
result[1] = BitConverter.ToUInt16(bytes, 2);
break;
case ParseFormat.DCBA:
// 完全反转:DC BA
result[0] = ReverseUShort(BitConverter.ToUInt16(bytes, 0));
result[1] = ReverseUShort(BitConverter.ToUInt16(bytes, 2));
break;
}
return result;
}
/// <summary>
/// 反转 ushort 的高低字节(B A ↔ A B)
/// </summary>
private static ushort ReverseUShort(ushort value)
{
return (ushort)((value >> 8) | (value << 8));
}
1.2 bool 类型写入
这里涉及一点思路转换,把ushort转换为16bits,每个bit对应一个bool状态,更改对应的bit后,得到更新后的ushort值,按照int转换为 ushort[]。
private static ushort[] ConvertIntToTwoUShorts(int value)
{
byte[] bytes = BitConverter.GetBytes(value);
return new ushort[]
{
BitConverter.ToUInt16(bytes, 0), // 高16位
BitConverter.ToUInt16(bytes, 2) // 低16位
};
}
2. 按ushort读取解析
NModbus 读寄存器API:
ushort[] ReadHoldingRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints);
2.1 解析float类型
一个float占用4个bytes,也就是两个ushort,所以将两个ushort转换为一个float
/// <summary>
/// 【反向】将两个 ushort 根据指定格式 还原为 float
/// </summary>
/// <param name="values">两个ushort:[高16位, 低16位]</param>
/// <param name="parseFormat">解析格式 ABCD/BADC/CDAB/DCBA</param>
/// <returns>还原后的float</returns>
private static float ConvertTwoUShortsToFloat(ushort[] values, ParseFormat parseFormat)
{
if (values == null || values.Length != 2)
throw new ArgumentException("必须传入长度为2的ushort数组");
ushort high = values[0];
ushort low = values[1];
byte[] bytes = new byte[4];
switch (parseFormat)
{
case ParseFormat.ABCD:
// AB CD → 字节顺序 [CD][AB]
Buffer.BlockCopy(BitConverter.GetBytes(low), 0, bytes, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes(high), 0, bytes, 2, 2);
break;
case ParseFormat.BADC:
// BA CD → 低字反转,高字不变
Buffer.BlockCopy(BitConverter.GetBytes(ReverseUShort(low)), 0, bytes, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes(high), 0, bytes, 2, 2);
break;
case ParseFormat.CDAB:
// CD AB → 高低字互换
Buffer.BlockCopy(BitConverter.GetBytes(high), 0, bytes, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes(low), 0, bytes, 2, 2);
break;
case ParseFormat.DCBA:
// DC BA → 高低字都反转
Buffer.BlockCopy(BitConverter.GetBytes(ReverseUShort(low)), 0, bytes, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes(ReverseUShort(high)), 0, bytes, 2, 2);
break;
default:
throw new NotSupportedException("不支持的解析格式");
}
return BitConverter.ToSingle(bytes, 0);
}
2.2 解析bool类型
这里拿到的依然是一个ushort,然后看该bool量对应的bit在第几位。下面仅列出ushort对应到int的逆向转换。
private static int ConvertTwoUShortsToInt(ushort[] values)
{
if (values == null || values.Length != 2)
throw new ArgumentException("必须传入长度为2的ushort数组");
byte[] bytes = new byte[4];
Buffer.BlockCopy(BitConverter.GetBytes(values[0]), 0, bytes, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes(values[1]), 0, bytes, 2, 2);
return BitConverter.ToInt32(bytes, 0);
}