I receive 2 values, 1 and 213. Now these two numbers are actually stored as 8 binary bits. The values of those bits are 00000001 and 11010101 respectively (HERE is a convenient calculator). The value I want is the 16 bit int variable that results when these two are added together. ie I want the number represented by 0000000111010101; that would be 469. Sounds like I need to do some Arduino data type conversion.
I Googled around and asked one of my computer science friends, but there doesn't appear to be a ready made solution for this. I should point out that if you are reading the value directly from a serial port, you can just use parseInt(). My problem is that I am using an external library to get the sensor data and then need to combine the bytes afterward.
After some deliberation I acquired a list of ways I thought I could combine two 8-bit bytes into one 16- bit int (or short) variable. Some of these ways I have not pursued, but a few I have. I have tested them, and clocked the processing times for a few values on an Arduino Mega2560 r3.
Combination using bitRead(): 108 microseconds
This is the first method I thought of. It reads each bit in the byte and then copies it over to the int. This is not very efficient, but it does get the job done. It does take quite a bit more clock time than the other methods, but it is a rather intuitive approach.
int BitReadCombine( unsigned int x_high, unsigned int x_low)
{
int x;
for( int t = 7; t >= 0; t--)
{
bitWrite(x, t, bitRead(x_low, t));
}
for( int t = 7; t >= 0; t--)
{
bitWrite(x, t + 8, bitRead(x_high, t));
}
return x;
}
Combination using bit shifting: 4 microseconds
In this method, a bit shift operator is applied to move the high byte into the correct position in the final int. This, to me, is the most elegant solution. I don't know that you will find anything much faster. Note that the micros() function has a resolution of 4, so measuring something like this directly is a little difficult. Code modified from HERE.
int BitShiftCombine( unsigned char x_high, unsigned char x_low)Combination using multiplication: 4 microseconds
{
int combined;
combined = x_high; //send x_high to rightmost 8 bits
combined = combined<<8; //shift x_high over to leftmost 8 bits
combined |= x_low; //logical OR keeps x_high intact in combined and fills in //rightmost 8 bits
return combined;
}
This method is basically identical to the one above. I read conflicting arguments for whether it would be any slower or not. If it is, it is pretty negligible. Basically, instead of shifting the bits using a bit shift, I just multiply by 256. This is like if I wanted to shift the "1" in 10 to the 1000th place. I would multiply by 100 (10^2). In binary I want to shift it 8 places, so I multiply the variable by 2^8 or 256.
int MultiplicationCombine(unsigned int x_high, unsigned int x_low)
{
int combined;
combined = x_high;
combined = combined*256;
combined |= x_low;
return combined;
}
Other possibilities
It was suggested to me that I should use strings. This seems like a rather roundabout way of getting there, but I would think it would work. You need to combine each byte into a binary string and then concatenate them by adding them together. Then you can convert them back to an int and you're good to go. This could be accomplished several ways with one being the itoa and atoi functions.
Edit: Thanks to Nigel Parker for adding another method and elaborating calculating the speed of each more precisely. In his comment he details how to use the union constructor to combine bytes into different data types. I have saved his code in a sketch available HERE. He notes that this method can be faster than any of the previous methods mentioned when used correctly.
Edit: Thanks to Nigel Parker for adding another method and elaborating calculating the speed of each more precisely. In his comment he details how to use the union constructor to combine bytes into different data types. I have saved his code in a sketch available HERE. He notes that this method can be faster than any of the previous methods mentioned when used correctly.
Conclusion
There are probably other methods of combing bytes into an int that I have not looked at. If so, post a link in the comments. That will only broaden the scope of this post. All of the methods here could be adapted to match a 32 bit long if necessary and could be put into an unsigned variable just as easily as a signed one. With that in mind, I will probably use the bit shift method from now on. It seems like the most elegant and efficient solution.
I hope this post helped someone out. If you want my script to check the clock times for yourself, find it HERE. It also might help if you're a little fuzzy on exactly what is going on. If something doesn't work for you, comment below, and I'll do my best to help you.
-Matthew