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); } } }