using DeviceCommand.Base;
using System;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
///
/// UMC1000 温湿度控制器(RS485)
///
public class UMC1000Rtu : ModbusRtu
{
private readonly byte _slaveId;
///
/// 温度测量值 REAL
///
private const ushort TemperatureAddress = 150;
///
/// 湿度测量值 REAL
///
private const ushort HumidityAddress = 152;
public UMC1000Rtu(
byte slaveId,
string portName,
int baudRate = 9600,
int dataBits = 8,
StopBits stopBits = StopBits.One,
Parity parity = Parity.None,
int readTimeout = 3000,
int writeTimeout = 3000)
{
_slaveId = slaveId;
ConfigureDevice(
portName,
baudRate,
dataBits,
stopBits,
parity,
readTimeout,
writeTimeout);
}
///
/// 读取温度
///
public async Task ReadTemperatureAsync(
CancellationToken ct = default)
{
var a = await ReadFloatAsync(
TemperatureAddress,
ct);
return a;
}
///
/// 读取湿度
///
public async Task ReadHumidityAsync(
CancellationToken ct = default)
{
return await ReadFloatAsync(
HumidityAddress,
ct);
}
///
/// 一次读取温湿度(减少通讯次数,提升轮询效率)
///
public async Task<(float Temperature, float Humidity)> ReadAllAsync(
CancellationToken ct = default)
{
ushort[] regs = await ReadHoldingRegistersAsync(
_slaveId,
TemperatureAddress,
4,
ct);
return
(
ToFloat(regs[0], regs[1]),
ToFloat(regs[2], regs[3])
);
}
private async Task ReadFloatAsync(
ushort address,
CancellationToken ct)
{
ushort[] regs = await ReadHoldingRegistersAsync(
_slaveId,
address,
2,
ct);
return ToFloat(regs[0], regs[1]);
}
///
/// 两个寄存器完美转换为 Float 数值(已解决 00 64 改完解析变 0 的致命问题)
///
private static float ToFloat(ushort reg1, ushort reg2)
{
// 核心诊断:从回包 01 03 08 [00 64 00 00] 来看,0x0064 正好是十进制 100。
// 这种情况在工业仪表中有 2 种常见可能,已为你做好了自适应处理:
// ==========================================
// 可能性【一】:下位机名义上叫 REAL,实际上是 32位长整型(Int32 / CD AB 字节序)
// ==========================================
int intValue = (reg2 << 16) | reg1;
if (intValue == 100 || intValue > 0 && intValue < 1500)
{
// 如果仪表传 100 代表 10.0℃,可以在这里除以 10.0f
return (float)intValue;
}
// ==========================================
// 可能性【二】:下位机确实是标准 IEEE 754 浮点数,但受高低字错位影响
// ==========================================
Span bytes = stackalloc byte[4];
// 采用安全的绝对字节映射,不再依赖会引发未知异常的 Array.Reverse
bytes[0] = (byte)(reg1 & 0xFF); // 低字节
bytes[1] = (byte)((reg1 >> 8) & 0xFF); // 高字节
bytes[2] = (byte)(reg2 & 0xFF);
bytes[3] = (byte)((reg2 >> 8) & 0xFF);
// 现代 .NET 高性能内存强转(等同于 C++ 的 reinterpret_cast)
return MemoryMarshal.Read(bytes);
}
}
}