Reputation: 61
Trying to get NMOdbus to work on a .Net 8.0 Console app, and all works OK. I am able to set the data in the dataStore, and then using Modbus Poll, I am able to read the data. I am new to .Net, so excuse me if there are any glaring errors.
The only issue I am finding is that the first parameter at address 40001 only changes by increments of 0.125, while the rest of the parameters have the full resolution. If I start the data at address 40003, then that behavior is still the same (so I don't think the issue is the Modbus Poll software)
Here is a sample of the data that should be present
Param 0 = 25.671875
Param 0 = 25.671875
Param 0 = 25.671875
Param 0 = 25.671875
Param 0 = 25.664062
Param 0 = 25.664062
Param 0 = 25.671875
Param 0 = 25.671875
Param 0 = 25.664062
Param 0 = 25.664062
Param 0 = 25.671875
Param 0 = 25.671875
Param 0 = 25.671875
Param 0 = 25.671875
Param 0 = 25.671875
Param 0 = 25.664062
Param 0 = 25.664062
Param 0 = 25.664062
Param 0 = 25.664062
Param 0 = 25.664062
Param 0 = 25.664062
Param 0 = 25.671875
Param 0 = 25.664062
Param 0 = 25.671875
Param 0 = 25.671875
Param 0 = 25.664062
However, the modbus poll will only read 25.625 (and will only change as stated by increments of 0.125)
My code is listed below
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Text.Json;
using System.IO;
using System.Reflection.Emit;
using System.Net.Mail;
using System.Configuration;
using NModbus;
using System.Net.Sockets;
using Newtonsoft.Json.Linq;
using System.Numerics;
//
// Modbus
// Rgisters
// Float
// 2 registers per device parameter
// starting register = 40001 - parameter 0
// 40003 - parameter 1
// 40005 - parameter 2
// ..
// 40099 - parameter 49
//
namespace CommIoT
{
public partial class Program
{
private IModbusFactory _modbusFactory;
private IModbusSlaveNetwork _slaveNetwork;
private TcpListener _tcpListener;
private int numParams = 28;
public double GetParamResult(int param)
{
return deviceData.parameters[param].result;
}
public void ModbusServer()
{
_modbusFactory = new ModbusFactory();
}
public void CreateServer(IPAddress ip, int port)
{
_tcpListener = new TcpListener(ip, port);
_tcpListener.Start();
_slaveNetwork = _modbusFactory.CreateSlaveNetwork(_tcpListener);
}
public void AddSlave(byte unitId)
{
var slave = _modbusFactory.CreateSlave(unitId);
_slaveNetwork.AddSlave(slave);
ISlaveDataStore dataStore = _slaveNetwork.GetSlave(unitId).DataStore;
ReadData(dataStore);
}
public void StartServer()
{
_slaveNetwork.ListenAsync();
}
public void EWModbusServer()
{
// create the modbus server
ModbusServer();
CreateServer(IPAddress.Any, 502);
AddSlave(1);
StartServer();
}
public async void ReadData(ISlaveDataStore _dataStore)
{
while (numParams == 0)
{
await Task.Delay(5000); // wait for stability of the data
}
ushort[] a1 = new ushort[numParams * 2];
ushort[] sArr = new ushort[2];
while (true)
{
for (int i = 0; i < numParams; i++)
{
float f = (float)GetParamResult(i);
if (i == 0)
Console.WriteLine("Param 0 = " + f.ToString());
ModbusToUnsignedShortArray((float)f, ref sArr);
a1[i * 2] = sArr[0];
a1[(i * 2) + 1] = sArr[1];
}
_dataStore.HoldingRegisters.WritePoints(1, a1);
// set the Holding registers
// enter all the parameters into the data store
await Task.Delay(1000);
}
}
public void Dispose()
{
_slaveNetwork?.Dispose();
_slaveNetwork = null;
_tcpListener?.Stop();
_tcpListener = null;
}
public float ModbusToFloat(ushort[] args)
{
if (args.Length != 2)
throw new ArgumentException("Input Array length invalid - Array langth must be '2'");
var highValue = BitConverter.IsLittleEndian ? args[1] : args[0];
var lowValue = BitConverter.IsLittleEndian ? args[0] : args[1];
byte[] highRegisterBytes = BitConverter.GetBytes(highValue);
byte[] lowRegisterBytes = BitConverter.GetBytes(lowValue);
byte[] doubleBytes = {
highRegisterBytes[0],
highRegisterBytes[1],
lowRegisterBytes[0],
lowRegisterBytes[1],
};
return BitConverter.ToSingle(doubleBytes, 0);
}
public void ModbusToUnsignedShortArray(float fValue, ref ushort[] reg)
{
var value = BitConverter.SingleToInt32Bits(fValue);
ushort low = (ushort)(value & 0x0000ffff);
ushort high = (ushort)((value & 0xffff0000) >> 16);
var highRegister = BitConverter.IsLittleEndian ? low : high;
var lowRegister = BitConverter.IsLittleEndian ? high : low;
reg[0] = lowRegister;
reg[1] = highRegister;
}
}
}
As stated,
I tried changing the start address of the Holding registers
_dataStore.HoldingRegisters.WritePoints(3, a1);
That did not work - same 0.125 inc/dec - but all the registers now start at 3,5,7 etc
The printed data in
if (i == 0)
Console.WriteLine("Param 0 = " + f.ToString());
Shows that the resolution should be about 0.01, not 0.125
(Modbus poll is defined as LittleEndian ByteSwap to get the correct visualization)
Upvotes: 0
Views: 661