Files
IOT/DeviceCommand/Devices/UMC1000Rtu.cs
“hsc” fa2f9f64c5 RTU添加
2026-06-12 15:29:18 +08:00

137 lines
4.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.
using DeviceCommand.Base;
using System;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace DeviceCommand.Devices
{
/// <summary>
/// UMC1000 温湿度控制器(RS485)
/// </summary>
public class UMC1000Rtu : ModbusRtu
{
private readonly byte _slaveId;
/// <summary>
/// 温度测量值 REAL
/// </summary>
private const ushort TemperatureAddress = 150;
/// <summary>
/// 湿度测量值 REAL
/// </summary>
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);
}
/// <summary>
/// 读取温度
/// </summary>
public async Task<float> ReadTemperatureAsync(
CancellationToken ct = default)
{
var a = await ReadFloatAsync(
TemperatureAddress,
ct);
return a;
}
/// <summary>
/// 读取湿度
/// </summary>
public async Task<float> ReadHumidityAsync(
CancellationToken ct = default)
{
return await ReadFloatAsync(
HumidityAddress,
ct);
}
/// <summary>
/// 一次读取温湿度(减少通讯次数,提升轮询效率)
/// </summary>
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<float> ReadFloatAsync(
ushort address,
CancellationToken ct)
{
ushort[] regs = await ReadHoldingRegistersAsync(
_slaveId,
address,
2,
ct);
return ToFloat(regs[0], regs[1]);
}
/// <summary>
/// 两个寄存器完美转换为 Float 数值(已解决 00 64 改完解析变 0 的致命问题)
/// </summary>
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<byte> 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<float*>
return MemoryMarshal.Read<float>(bytes);
}
}
}