How to create a 32bit number from two 16bit ints (high, low)

I am reading two values from a Modbus, which are supposed to become a single number.

Unit_Serial_Number.(lo).: F81A | 63514
Unit_Serial_Number.(hi).: 1F16 | 7958

The serial number should be: 139030

When I put the serial number into a calculator, I can see 2 and 1F16
image
... but how do I get the lo word into the mix?

When I take 139030 and subtract the 0x1f16 (7958) I get 131072. Then divide it by 2 and get 65536. which is 1 more than the value of 0xffff.
Meaning, playing with these numbers shows me some relationship.
But I do not get the logic of it.

Any hints appreciated.

something like this maybe,,,

void setup() {
  Serial.begin(115200);

  uint16_t serial_words[2] = {0xF81A, 0x1F16}; //lo, hi. check your boards endiness!

  uint32_t full_serial = 0;
  memcpy(&full_serial, serial_words, 4);
  Serial.println(full_serial, HEX);
  Serial.println(full_serial, DEC);
}

void loop() {
  // put your main code here, to run repeatedly:

}

hope that helps...

Thanks... it is not about printing; the serial output is only interim until I publish the data via MQTT.

I translated what you wrote to:

uint32_t make_32bit_word(uint16_t hi_word, uint16_t lo_word)
{
    uint16_t words_16bit[2] = {hi_word, lo_word};
    uint32_t word_32bit = 0;

    memcpy(&word_32bit, words_16bit, 4);

    return word_32bit;
}

and get:

Unit_Serial_Number.(lo).: F81B | 63515
Unit_Serial_Number.(hi).: 1F16 | 7958
Unit_Serial_Number......: 139030 | 4162526998

twisting hi lo will produce 521599004.

So there is something I am missing.

This does not equate to 139030. Where did you come to that conclusion?

0x1F16F81A is 521599002 in decimal.

Well, I know what the serial number is.
It is stored as two unsigned ints.

Adding the number by concatenating does not seem to be the solution to the problem.

When I look at the calculator in the O.P. I see the 2nd byte from the bottom to be a 2.

This means 2 x something.
Like 2 x 65536.
If I add this to hi_word being 7958 I get 139030.

There is something I need to do with the 2 or get to the 2. Bit shifting, OR-ing... something, I am not familiar with.

[Worst case, either one or both of the two ints I am reading are incorrect. But I do not believe this to be the case, given the commercial product I am interfacing with.)

Are you sure you are looking at the correct 2 bytes from the MODBUS ? Maybe you're out by two bytes somewhere?

If that is the serial number then you should be getting

Lo bytes 0x1F16
Hi bytes 0x0002

Thanks for hanging in there... :slight_smile:
I just checked...
I am pulling the right addresses, but the documentation seems out.
There is a value before the lo word, which should belong to the previous word.

Well case closed! I am not getting the right value from this address (lo_word).

Thank you all.

Didn't see the post... yes, these are the two words I should be seeing.

I did some further digging, based on my assumption that a commercial product should not have this problem (can, but unlikely)... I reviewed my code.

I have grouped the 106 registers into lots that belong together... these words being in a group of 13 registers. I only had 12 in there! After adding the missing one, the serial number appears correctly.

Unit_Serial_Number.(lo).: 1F16 | 7958
Unit_Serial_Number.(hi).: 2 | 2
Unit_Serial_Number......: 139030

This function returns the right result:

uint32_t make_32bit_word(uint16_t hi_word, uint16_t lo_word)
{
    uint16_t words_16bit[2] = {lo_word, hi_word};
    uint32_t word_32bit = 0;

    memcpy(&word_32bit, words_16bit, 4);

    return word_32bit;
}

Again, thanks all for your support.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.