Go Down

Topic: Urgent - Split Long into 2 Int using BitShift (Read 6702 times) previous topic - next topic

MatrixGTI

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.

Actually I do this :

HighINT = ValueLong / 32767;
LowINT = ValueLong - (HighINT * 32767);

regs[MB_REG4] = HighINT;
regs[MB_REG5] = LowINT ;

It works good but it need a lot of time when ValueLong is big

I need to do the same operation using bitshift, something like:

HighINT = (ValueLong >> 16) & 0x0000ffffl;
LowINT  = ValueLong & 0x0000ffffl;

regs[MB_REG4] = HighINT;
regs[MB_REG5] = LowINT;

I'm not expert in bits operation, I hope that someone can correct this code for me.

Thanks in advanced !  ;)

Matrix

AWOL

#1
Jan 20, 2011, 04:09 pm Last Edit: Jan 20, 2011, 04:14 pm by AWOL Reason: 1

Dividing by 32767 'works good'?
That's where your problem is; your definition of 'good' is flawed.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

MatrixGTI

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.

AWOL

It doesn't work.
It may do something, but it isn't correct.
It may help to see the problem if you write 32767 out in hex.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

MatrixGTI

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)

rebuildLong = ( HighINT * 32767) + LowInt

I need the same exactly results.... but faster  :)

AWOL

You've already posted a bitshift method that works, so why not use it?
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

robtillaart

#6
Jan 20, 2011, 05:05 pm Last Edit: Jan 20, 2011, 06:19 pm by robtillaart Reason: 1
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.

---------

The first part is not correct:

HighINT = ValueLong / 32767;
LowINT = ValueLong - (HighINT * 32767);

should be

HighINT = ValueLong / 32768;
LowINT = ValueLong - (HighINT * 32768);

or

HighINT = ValueLong / 32768;
LowINT = ValueLong  % 32768;


[edit]Sorry: the magic number must be 65536L as stated below. Too eager to answer  :-[  [/edit]


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

AWOL

#7
Jan 20, 2011, 05:07 pm Last Edit: Jan 20, 2011, 05:09 pm by AWOL Reason: 1
Better still, use 65536.  See reply #1

;)
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

jraskell

Just use:

HighINT = ValueLong >> 16;
LowINT  = ValueLong;

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.

MatrixGTI

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.


westfw

Code: [Select]
HighINT = (ValueLong >> 16) & 0x0000ffffl;
LowINT  = ValueLong & 0x0000ffffl;

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.

jraskell

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').

MatrixGTI

#12
Jan 20, 2011, 05:44 pm Last Edit: Jan 20, 2011, 05:51 pm by MatrixGTI Reason: 1
I try this code as test, maybe can help to find  mistakes

int H;
int L;
long ValueLong;

void loop(){

ValueLong = -1;

H = ( ValueLong >> 16) & 0x0000ffffl;

L = ValueLong & 0x0000ffffl;


Serial.print(H,DEC);
Serial.print("-");
Serial.println(L,DEC);

delay(500);

}

Results are H = -1 L = -1

if ValueLong = 32769  H = 0 L = -32766   :(

same results without masks

I'm counfused

robtillaart

try using print(..., BIN) to see the bit patterns ... thn you see what happens ..
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

MatrixGTI

#14
Jan 20, 2011, 06:01 pm Last Edit: Jan 20, 2011, 06:03 pm by MatrixGTI Reason: 1
With -1 as ValueLong I read on serial monitor:

L = 11111111111111111111111111111111
H = 11111111111111111111111111111111

both with mask or not


with 32769 I read:

H = 0
L= 11111111111111111000000000000001

Go Up