I have a 48 bit unsigned integer that I’m receiving in three WORDs of data (via Modbus). I need to combine these into one number (Flow Total). I’ve tried accessing the LREAL variable by its bits:
lrealVariable.0 := wordVariable.0;
lrealVariable.1 := wordVariable.1;
etc.
But it seems the bits of the LREAL variable are not accessible the same way the WORD bits are.
I then tried making an array of four WORDs but AS will not equate the LREAL to the array of words:
lrealVariable := arrayVariable;
Possibly a case for a Derived Data Type…but I’m having trouble sorting out the help document surrounding that. I’ve created Structures many times but is there a way to create two types of data that point at the same memory addresses?
Any advise is appreciated.
Thanks
1st you copy memory of the wordVariable1 (2 bytes) into 2 first bytes of the lrealVariable.
2nd you copy memory of the wordVariable2 (2 bytes) into bytes 3 and 4 of the lrealVariable
Finally you copy memory of the wordVariable3 (2 bytes) into bytes 5 and 6 of the lrealVariable
If you want you can avoid using SIZEOF function that for the explanation
Thanks for the reply Florent. I copied your example and substituted my variables. It compiles and I can enter values into wordVariable1,2 and 3 but the value in lrealVariable is not as expected. I am entering a value of 1 into the word variables, one at a time and all instances give me a very small number (e.g. 4.94065E-324).
What I’m expecting(hoping) to see is if:
wordVariable1 = 1
wordVariable2 = 0
wordVariable3 = 0
binary representation of lrealVariable is: 0000 0000 0000 0001
lrealVariable value = 1
I’m still wrapping my head around brsmemcpy so please let me know if I’m misunderstanding. I’ll continue to work with it but any insight is appreciated.
Thanks
Dave
Just adding that I like the following IEEE-754 floating point converter for checking what number(s) can be represented as floating point/calculating floating point error:
In your case you can also just copy directly to the mantissa if you know the bits of the mantissa. You also need to have an exponent of 1 in that case.
Oh yeah, that’s my bad!
I answered too fast, bit representation of float64 isn’t the same as uint64.
Thanks @michael.bertsch and @eric.oldfield for this !
I will create an example and test it !
I don’t think you answered incorrectly, given the information in the original post. My read is that it seems to be what David was looking for.
The question that’s been bugging me, is who gives 48/64 bits of a floating-point value and expects it to be in any way accurate. Are we to assume the last 16-bits in the Mantissa are all 0’s? Then why not use a 32-bit floating-point and have roughly the same accuracy while using 1 fewer register? It’s weird.
If I were to guess, those 48-bits actually need to be manually converted (ex. interpret as a 48-bit long integer, then divide by 10 or 1000), but that would be part of the information from the Modbus device.
Bonus thought: If the data point is total (accumulated) flow, a basic value that always counts up, then floating-point values losing precision at higher values wouldn’t be ideal. Integers work better, even if they eventually roll over.
I knew about the formatting on floats…so I should have clued into that.
To Austin’s point:
This is the first time I’ve seen this format from a flow meter as well (McNaught flow meter). And you are correct, it is in fact a UINT48 value and I then need to apply three decimal places.
e.g. - If the total is 1,111,111.111 the data is 0x0000 0x423A 0x35C7
The reason I chose to use the LREAL data type is that it’s the only data type larger than 32 bits that I can see…? I should have included that information in the original post…perhaps there’s a better way? I’m wide open to other suggestions.
I’ll see if I can get Florent’s revised code to work in the meantime.
Another possibility is to make a function in C, because there we have a 64 bit integer.
This way we can convert up to 8 bytes / 4 words / 2 longs into an LREAL.
Function declaration and body in a library:
double BYTEsToLREAL(plcbyte Input[8])
{
/* convert input array to 64 bit integer */
long long int value = * ((long long int *)&Input[0]);
return ((double)value);
}