Hi,am trying to communicate with power-factor controller [Selec APFC 148-312] using modbus RTU,am following example sketch from modbusmaster library. am able to get the raw data from the instrument but data structure seems to be in decimal format, can someone help me to convert this into float.thank you
#include <ModbusMaster.h>
#define MAX485_DE 3
#define MAX485_RE_NEG 2
// instantiate ModbusMaster object
ModbusMaster node;
void preTransmission()
{
digitalWrite(MAX485_RE_NEG, 1);
digitalWrite(MAX485_DE, 1);
}
void postTransmission()
{
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
}
void setup()
{
pinMode(MAX485_RE_NEG, OUTPUT);
pinMode(MAX485_DE, OUTPUT);
// Init in receive mode
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
// Modbus communication runs at 9600 baud
Serial.begin(9600);
// Modbus slave ID 1
node.begin(1, Serial);
// Callbacks allow us to configure the RS485 transceiver correctly
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
}
void loop()
{
float result;
result = node.readInputRegisters(0x30000, 10);
if (result == node.ku8MBSuccess)
{
Serial.print("V1N: ");
Serial.println(node.getResponseBuffer(0x01));
Serial.print("V2N: ");
Serial.println(node.getResponseBuffer(0x02));
Serial.print("V3N: ");
Serial.println(node.getResponseBuffer(0x03));
Serial.print("Vavg: ");
Serial.println(node.getResponseBuffer(0x04));
Serial.print("V12: ");
Serial.println(node.getResponseBuffer(0x05));
Serial.print("V23: ");
Serial.println(node.getResponseBuffer(0x06));
Serial.print("V31: ");
Serial.println(node.getResponseBuffer(0x07));
Serial.print("L-L avg: ");
Serial.println(node.getResponseBuffer(0x08));
}
delay(1000);
}
1 Answer 1
I'm not sure this can really be considered topical, but someone wanting to read floating point numbers over MODBUS with an Arduino might get something out of it. Also I have no way to test this really. But here goes:
Your MODBUS map shows V2N at 30002, and you notice 30003 is not mentioned in the map. Your voltage from phase two to neutral appears to be encoded into two consecutive 16-bit registers, which is a somewhat normal scheme for conveying 32bit floats via MODBUS, from what I can tell. So, your values of 17280
and 9830
are two halves of a 32-bit floating point number. In hex, 0x4380 and 0x2666. These seem to be taken together as 0x43802666 as the bit pattern for 32-bit float.
A function like this would allow you to extract your 32-bit float data from your separate 16-bit MODBUS register reads:
float modbus_16bit_register_pair_to_float(uint16_t a, uint16_t b) {
uint32_t combined = ((uint32_t)a << 16) | b;
float f;
memcpy(&f, &combined, sizeof f);
return f;
}
There are lots of ways you could do this. This code assumes that the float
type's endian matches the uint32_t
type's endian, and that float
is 32-bit, which is common but not strictly standard.
Running this on 17280
and 9830
gives 256.3 (rounded), which doesn't perfectly match other output, but I suspect that's just because the reading is varying.
-
1Thank You Sir. it worked.Ragaven N– Ragaven N2021年08月15日 20:44:57 +00:00Commented Aug 15, 2021 at 20:44
Serial.println()
converts its argument to decimal, for the purpose of printing it as text. The authors of this method assumed that most humans prefer reading decimal rather than binary. Note thatSerial.println()
can be told (by a second argument) to use a different base.