Hi All,
I have this problem and I did not found a solution :-/
I have a Signed Long variable that come from an encoder reading, I need to split it into 2 Signed Int to be able to send them to a PC using ModBus Slave over serial.
yes it works but increasing the long number will increase the loop time from 1 mS to more than 4 mS and it is not good for me. Anyway the conversion works.
EMH, I'm sure that it works.
I test it comparing the value of original Long on Arduino and the rebuilded one on the PC side doing the inverse math ( Software on PC side is VB6)
Looks to me like the shift you posted is correct and should work.
Question: The highint and lowint are they signed or unsigned?
One of the things that may happen with shift operations is sign extension, so maybe a cast to unsigned long is needed to make the >> 16 work correctly.
And be done with it. The masking is unnecessary. The results won't match your other method, but that is because, as AWOL has correctly pointed out, your other method is incorrect.
Both L & H int are signed and I need it because my Long must be Signed, Encoder can count + or - .
I dont know how BitShift works with sign
The math of the first post works even if you divide the long value by any number lower that 32767, on the worst case I cant reach the maximum Long extension but it is a very remote possibility ( > 1 milion)
Anyway the problem is not the result but the speed of the loop.
I try with >> 16 as in the #1 post but did not work.
I try >>15 to leave 1 bit for sign and it works only for L value
I dont have the knowledge base to understand this bit operation.
Those look OK. (better than the 32767 examples!)
There may be sign issues; Shift operation is not fully specified for signed numbers, but since you're masking things anyway you should get the correct results in any case.
Bitwise manipulation in general doesn't care one bit (no pun intended) about the sign or format of the variable they are operating on.
If you decompose a 4 byte variable into two 2 byte variables, and then later recompose them back into a 4 byte variable, the bit patterns will remain identical.
That's not to say there won't be any sign issues, but they will not be related in any way to the bitwise operations (for example, there may be endian problems if you are transferring the data between platforms with different endian'ness').
L = 11111111111111111111111111111111
H = 11111111111111111111111111111111
because both L & H & ValueLong are signed, 1111...11 will read as -1 for all three of them. Bitwise it is a correct split.
Another way to split your long is to use an union, a less used construct in C++, A union has multiple var's mapped upon the same memory space:
union split_t
{
int I[2];
long ValueLong;
} X;
void setup()
{
Serial.begin(115200);
}
void loop()
{
X.ValueLong = -1;
int H = X.I[0];
int L = X.I[1];
Serial.print(H, DEC);
Serial.print(" = ");
Serial.println(L,DEC);
delay(500);
}
The union split_t could be extended with unsigned long or an array of four bytes. Although it seems that no math is involved the indexing of the array takes some cpu cycles ...
I'm not quite sure what your expectations are here. The intermediate int decimal values will in no way correlate to the original long decimal value. If they are only being used as a necessary step to transfer the entire data, then that doesn't matter.
What matters is that the bit representation is maintained.
Say you have a long value of (just for example) 1,582,081.
It's binary representation would be:
00000000 00011000 00100100 00000001
If you then assign that value to two ints with bitwise shifting, you would end up with
high int 00000000 00011000
low int 00100100 00000001
If you then properly recompose that back into a new long, that new long will have the same decimal value as the previous one (assuming the binary representation of that decimal value is the same across any platform transitions).
You could use unsigned ints for your intermediate variables and it wouldn't make a difference. You could even use 4 bytes or chars instead.
With -1 as ValueLong I read on serial monitor:
L = 11111111111111111111111111111111
H = 11111111111111111111111111111111
That looks completely correct. Signed ints are stored in a twos complement format. Google it for more info on how twos complement works, and why it's an ideal format to use for signed ints.