i am using Arduino 1.0 with UNO board!
I am writing some new code and i am using bitshift to assign 5 bytes to a long var.
The code is:
address = a<<16 | b<<12 | c<<8 | d<<4 | e;
address is the long var and the a, b, c, d ,e are the bytes!
Everything is ok except the a<<16. This does nothing to the long var!
I wrote a test function where i "moved" the a byte from the low nibble to the high nibble of the long.
When it reaches the a<<16 then the long is 0x00000000 instead of 0x000F0000!
The same happens if i use brackets and if a is cast to a long! This is really weird!
dhenry what do you mean unions and pointers? An example maybe would help!
Using union or pointers to reconstitute a different data type is actually fairly common.
The solution I will provide you is built on that and takes just two instruction cycles to shift any number of bits (less than 8 obvious as you can break any shifts down). It is a hardware based solution available to any avr.
I will let you guys think about it for a while though.
Btw, if you are using those lower-end avrs, you have a hardware 4 / 12-bit shifter.
dhenry:
The solution I will provide you is built on that and takes just two instruction cycles to shift any number of bits (less than 8 obvious as you can break any shifts down). It is a hardware based solution available to any avr.
Well, let's see it.
The compiler generated this reasonably-efficient code to shift left 4 bits:
Its more subtle than that - by default an expression is promoted to the widest type present in it.
Here the constant 16 is of type int and is thus 16 bits on the Arduino. An expression of the form
byte << int widens its result to int. Thus the shift is done as a 16 bit shift after the byte 'a' is widened
to 16 bits. (If 'a' was of type char (which is signed) the widening would propagate the sign into the top
8 bits of the 16 bit value before the shift). However a shift of 16 still returns zero of course and the cast is needed:
psyche:
a, b, c, d ,e are the bytes!
Everything is ok except the a<<16. This does nothing to the long var!
What do you expect? A byte is 8 bits. You shift it left 16 bits. What is left? Zero.
Its more subtle than that - by default an expression is promoted to the widest type present in it.
Here the constant 16 is of type int and is thus 16 bits on the Arduino. An expression of the form
byte << int widens its result to int. Thus the shift is done as a 16 bit shift after the byte 'a' is widened
to 16 bits. (If 'a' was of type char (which is signed) the widening would propagate the sign into the top
8 bits of the 16 bit value before the shift). However a shift of 16 still returns zero of course and the cast is needed:
(Assuming 'b' only contains 4 useful bits)
[/quote]
I tried that too but it didn't work! I also updated to 1.0.1 but still no luck.
The only method that works is with union! I have managed to make it work that way! Thank you all and mostly dhenry for the hint!
I am still open to new suggestions!
psyche:
The same happens if i use brackets and if a is cast to a long! This is really weird!
Yes, that is really wierd. I second AWOL's call for your code (using long) and the result of running that code. You seem to be constructing a 20-bit value from five four-bit values, and it should be possible to achieve that.
MarkT:
Its more subtle than that - by default an expression is promoted to the widest type present in it.
Here the constant 16 is of type int and is thus 16 bits on the Arduino. An expression of the form
Mostly true, though not complete.address = ((long)a)<<16 | b<<12 | c<<8 | d<<4 | e;
If you have a mixture of just char and short items, the expression is converted to int
The right side of a shift does not cause the left side to be promoted
The promotion does not occur until the sub-expression is validated, so in your example, (b<<12) would still be evaluated as an int. If b happened to be 16..31, it will create a negative number, which when converted to long will fill in all of the upper bits.
Ok the long (b) << 12 did the job BUT it doesn't work in the for loop!
Any reason why? If i remove the 2 "long" then the address is increased as it should! With the 2 "long" in there, what i get is the initial value and then i get the last value! Not any other values between the two, just min and max values! Weird!!!
AWOL:
Still waiting to see dhenry's code to perform the equivalent of a four bit shift with pointers and/or structs/unions.
I have a suspicion that it might be possible to achieve using bitfields, but even assuming you could muddle a way through to make it work the result would be pretty convoluted. Straight forward bit shifts offer a far more appropriate solution in this case.