I have data coming from a V9261F energy measuring chip (link to datasheet), that sends it data through a UART to my Arduino microcontroller. When I read register 0x0119, I read the active power measured by the chip. But the problem is that this feedback is in 32 bits 2's complement and I can not decode it.

UART communication

Starting from the 4th byte in the stream are the data bytes in which the measured variables are stored (see data sheet pg 56 - 57). For reading register 0x0119, this should be in databyte 10 - 11 - 12 and 13 (D1) respectively 0x55, 0xE7, 0x0E and for databyte 13 0x00.

So the feedback for the active power all the bytes combined I have is 0x000EE755 -> subtract 1 (for 1 complement) = 0x000EE754 -> invert it to become decimal number = 0xFFF118AB (4293990571 dec). But this insane big number should only represent an active power of 6.2 Watts.

What do I do wrong with converting from the 2's complement to decimal? How should this represent 6.2 watt?


I think you have a misunderstanding of what "2's complement" means. A positive 2's complement number is identical to a positive binary number (the most significant bit must be zero). So for 8 bits we have 0x00 (zero) to 0x7F (127). Numbers less than zero go from 0xFF (-1) to 0x80 (-128). To make a negative number positive so you can display it as a minus sign in front of a positive number you can calculate the 2's complement as you show above. Note the special case of 0x80.

So with 0x000EE754 you have a positive number of decimal 976724. There is a scaling factor between that and 6.2 of 6.3478E-6.

Probably what you want to do is to convert the number into a floating point number and do the calculations in floating point. It's already in 32-bit signed integer format.

| improve this answer | |

Two's complement is a format to describe negative numbers. It applies when the number is negative. Your calculations don't make any sense. https://en.wikipedia.org/wiki/Two%27s_complement

According to RTFM, the data format of the device is 32 bit 2's complement little endian. So given that your MCU is little endian (which is the case with AVR), you don't need to convert anything. Simply store the result in a int32_t.

The data format for UART is LSB first and the tool which made the picture seems to be aware. So if you have some data like 55e70e00, then that's the actual data read. Since it is little endian, it corresponds to hex 0x000ee755, decimal 976725. This is the value you should end up with after reading from the UART rx register. If this number makes sense, I have no idea.

2's complement doesn't matter since the number is positive in this case. A negative number would have a binary 1 in the MSB.

| improve this answer | |
  • \$\begingroup\$ OK thank you for clearing this up. I will check if no scaling factor is used with doing multipe load measurements. Rather strange that nothing from scaling factor is noted in the datasheets. \$\endgroup\$ – Bert Sep 15 '17 at 14:41
  • 2
    \$\begingroup\$ The statement "Two's complement is a format to describe negative numbers." is not accurate. The "two's complement" format describes all numbers, not just negative. It just becomes more interesting for negative numbers. \$\endgroup\$ – JoelFan Sep 15 '17 at 18:36
  • \$\begingroup\$ Rather, two's complement is a sign convention for representing integers. \$\endgroup\$ – chrylis -cautiouslyoptimistic- Sep 15 '17 at 22:10

The way I like to think about two's-complement numbers is to think about what happens to a the lower bits of a binary number when subtracting. If the bottom 4 bits of x are 0000 and the bottom four bits of y are 0001, then the bottom four bits of x-y are going to be 1111 regardless of what the bits are above them. This can easily be generalized for any particular number of bits (subtracting a number whose bottom bits express the value 1 from a number whose bottom bits express the value 0 will yield a number whose bottom bits are all set). Since that will work for any number of bits, it may be further generalized to say that subtracting one from zero will yield a number with an infinite number of bits set.

In practice, storing an infinite number of bits isn't practical. For any N>=1, however, all numbers within the range -(2^N) to (2^N)-1, however, all bits to the left of the Nth bit (counting leftward) will have the same value as the Nth bit itself, and thus need not be stored. Thus, when using an 8-bit two's-complement values, the value -1 isn't "really" 10000000, but is instead [infinite # of 1s]0000000, and the value 127 isn't 01111111, but [infinite # of 0s]1111111. Viewing things in this fashion will make it clear how conversions between different sizes of values should work.

For example, converting the 8-bit value to 16 bits would simply entail copying out part of the inifinite string of 1s or zeros, while converting a 16-bit value in the range -128..127 to 8 bits would entail dropping some duplicated bits. If a 16-bit number is outside that range, converting it to 8 bits would yield the value that would result from copying out the most singificant retained bit.

PS--applying the power summation formula 1+2+4+8... yields -1. That may seem nonsensical, but fits perfectly with how two's-complement math works. For any value of N, if the bottom N bits of a number are all set, adding 1 will yield a number whose bottom N bits are all clear. The only number for which the bottom N bits will be clear for all values of N is zero, and the only number which will yield 0 when 1 is added to it is, of course, -1.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.