Files
VacuumPressureMembranePoreS…/Service/ModbusTcpPlcService.cs

159 lines
5.3 KiB
C#
Raw Normal View History

2026-03-26 19:43:52 +08:00
using Modbus.Device;
using System;
using System.Net;
2026-02-27 16:58:02 +08:00
using System.Net.Sockets;
using System.Threading.Tasks;
namespace MembranePoreTester.Communication
{
public class ModbusTcpPlcService : IPlcService, IDisposable
{
private readonly PlcConfiguration _config;
private TcpClient _tcpClient;
private IModbusMaster _master;
public ModbusTcpPlcService(PlcConfiguration config)
{
_config = config;
}
private async Task EnsureConnectedAsync()
{
if (_tcpClient == null || !_tcpClient.Connected)
{
_tcpClient = new TcpClient();
await _tcpClient.ConnectAsync(_config.IpAddress, _config.Port);
_master = ModbusIpMaster.CreateIp(_tcpClient);
}
}
// 读取两个连续的保持寄存器转换为32位浮点数假设大端模式
private async Task<float> ReadFloatAsync(ushort startAddress)
{
await EnsureConnectedAsync();
2026-03-26 19:43:52 +08:00
var registers = await ReadHoldingRegistersAsync(startAddress, 2);
return UshortToFloat(registers[1], registers[0]);
2026-02-27 16:58:02 +08:00
}
2026-03-26 19:43:52 +08:00
2026-02-27 16:58:02 +08:00
public async Task<float> ReadPressureAsync() =>
2026-03-26 19:43:52 +08:00
await ReadFloatAsync(_config.PressureRegister);
2026-02-27 16:58:02 +08:00
public async Task<float> ReadWetFlowAsync() =>
2026-03-26 19:43:52 +08:00
await ReadFloatAsync(_config.WetFlowRegister);
2026-02-27 16:58:02 +08:00
public async Task<float> ReadDryFlowAsync() =>
2026-03-26 19:43:52 +08:00
await ReadFloatAsync(_config.DryFlowRegister);
2026-02-27 16:58:02 +08:00
2026-03-19 20:40:54 +08:00
public async Task WriteCoilAsync(ushort coilAddress, bool value)
{
await EnsureConnectedAsync();
await _master.WriteSingleCoilAsync(_config.SlaveId, coilAddress, value);
}
public async Task WriteRegisterAsync(ushort registerAddress, ushort value)
{
await EnsureConnectedAsync();
await _master.WriteSingleRegisterAsync(_config.SlaveId, registerAddress, value);
}
public async Task<bool> ReadCoilAsync(ushort coilAddress)
{
await EnsureConnectedAsync();
2026-03-26 19:43:52 +08:00
bool[] result = await _master?.ReadCoilsAsync(_config.SlaveId, coilAddress, 1);
2026-03-19 20:40:54 +08:00
return result[0];
}
2026-03-24 19:33:35 +08:00
public async Task<ushort[]> ReadHoldingRegistersAsync(ushort startAddress, ushort count)
{
await EnsureConnectedAsync();
return await _master.ReadHoldingRegistersAsync(_config.SlaveId, startAddress, count);
}
public async Task WriteSingleRegisterAsync(ushort registerAddress, ushort value)
{
await EnsureConnectedAsync();
2026-03-26 19:43:52 +08:00
int val = (int)value;
await _master.WriteMultipleRegistersAsync(1, registerAddress, intToushorts(val));
2026-03-24 19:33:35 +08:00
}
2026-03-26 19:43:52 +08:00
public async Task WriteMultipleRegistersAsync(ushort registerAddress, float value)
{
await EnsureConnectedAsync();
await _master.WriteMultipleRegistersAsync(_config.SlaveId, registerAddress, SplitFloatToUShortArray((float)value));
}
/// <summary>
/// Int转为ushort数组发送
/// </summary>
/// <param name="res"></param>
/// <returns>返回ushort数组</returns>
private ushort[] intToushorts(int res)
{
ushort ust1 = (ushort)(res >> 16);
ushort ust2 = (ushort)res;
return new ushort[] { ust2, ust1 };
}
/// <summary>
/// Float转为Ushort数组发送
/// </summary>
/// <param name="value"></param>
/// <returns>返回ushort数组</returns>
public ushort[] SplitFloatToUShortArray(float value)
{
byte[] floatBytes = BitConverter.GetBytes(value);
ushort[] ushortArray = new ushort[floatBytes.Length / 2];
for (int i = 0, j = 0; i < floatBytes.Length; i += 2, j++)
{
ushortArray[j] = BitConverter.ToUInt16(floatBytes, i);
}
return ushortArray;
}
/// <summary>
/// ushort转为float类型
/// </summary>
/// <param name="P1"></param>
/// <param name="P2"></param>
/// <returns>float型数据</returns>
public float UshortToFloat(ushort P1, ushort P2)
{
int intSign, intSignRest, intExponent, intExponentRest;
float faResult, faDigit;
intSign = P1 / 32768;
intSignRest = P1 % 32768;
intExponent = intSignRest / 128;
intExponentRest = intSignRest % 128;
faDigit = (float)(intExponentRest * 65536 + P2) / 8388608;
faResult = (float)Math.Pow(-1, intSign) * (float)Math.Pow(2, intExponent - 127) * (faDigit + 1);
return faResult;
}
2026-03-24 19:33:35 +08:00
2026-03-19 20:40:54 +08:00
// 新增读取压力(根据工位)
public async Task<float> ReadPressureAsync(int stationId)
{
ushort startAddress = stationId switch
{
1 => _config.PressureRegisterStation1,
2 => _config.PressureRegisterStation2,
3 => _config.PressureRegisterStation3,
_ => throw new ArgumentException("Invalid station")
};
return await ReadFloatAsync(startAddress);
}
2026-02-27 16:58:02 +08:00
public void Dispose()
{
_master?.Dispose();
_tcpClient?.Close();
}
}
}