Bit shifting, again!

Hey guys,

Still learning here, and not great at these bitwise operations. I have a protocol that specifies data be sent as 2 bytes, however the 2 most significant bits of any byte are reserved. That is, the two first bits must always be zero. So 00111111 is valid, but 11111111 is not.

That said, they're still 2-byte values. So how do I spit out a value like this for any given int? Up to 4095, I presume (12 bits total). Say I want to send 1000 for example, that would be 00000111 00101000. How do I do this programmatically in code?

Thanks!

Would I do this?

int a = 1000;

int MSB = a&0x0fc0 >> 6;
int LSB = a&0x003f;

Or something like that?

Thanks!

I think your way will work. As a matter of style, I would do it this way:

const int lower_6_bits = B00111111;
byte MSB = (a >> 6) & lower_6_bits;
byte LSB = a & lower_6_bits;

If you do the shift first, the mask is the same for both bytes.

-Mike

You're right, that's definitely clearer. Thanks!

To get MSB (top 8 bits) from a 16-bit variable you need to shift 8 bits right (not 6).

const unsigned int a = 1000;
byte MSB = (a >> 8) & 0x3f;
byte LSB = a & 0x3f;

Also observe type of MSB/LSB - they should be byte (8 bits).

BenF said, "To get MSB (top 8 bits) from a 16-bit variable you need to shift 8 bits right (not 6). "

My first reaction was, oops! He's right. Then I realized that we weren't trying to get the top 8 bits from a 16-bit variable, we were trying to get the top two bits of the least-significant byte and the bottom six bits of the most-significant byte. That's because we are trying to output the lower 12 bits of the variable, split into two bytes, with each byte having 6 of the 12 bits.

Each letter represents one bit, "A" is the least significant bit:

PONMLKJI HGFEDCBA

The low order byte we send out will have the bits:

FEDCBA

For the high order byte, we want to send:

LKJIHG

So we need to shift it down 6 positions.

-Mike

P.S. You're absolutely right that the data type for LSB and MSB needs to be "byte".

That's because we are trying to output the lower 12 bits of the variable, split into two bytes, with each byte having 6 of the 12 bits.

In that case you're doing just fine! :slight_smile:

As an exercise then perhaps you want to have a go at doing the reverse.

unsigned int a;
byte MSB = B00000111;
byte LSB = B00101000;

// combine lower 6 bits from MSB/LSB into lower 12-bit of a
a = ?

If you get this right - you will qualify as a post graduate bit/shifter :wink:

Too easy :slight_smile:

unsigned int a;
byte MSB = B00000111;
byte LSB = B00101000;

// combine lower 6 bits from MSB/LSB into lower 12-bit of a
a = ((unsigned int)MSB << 6) | LSB;

I'm not sure if the type cast is necessary, but it doesn't hurt anything and removes any doubt.

Regards,

-Mike

Too easy

This looks good!

I would always include the 16-bit typecast because as you suggests the result (potential bit loss) would otherwise depend on the compiler - and we don't want that (an alternative safe approach is to first move MSB to 'a' and then do the left shift).

If we don't know the value of MSB/LSB I would aslo add code to force the two upper bits to '0' as in the following:

MSB &= B00111111;
LSB &= B00111111;