Interaction Design WikiElectrical Engineering

Bit Shifting

Bit Shifting involves using bitwise operators to manipulate the individual bits in data. Most of the time, we are not so concerned with values at such a granular level, but there are a number of situations when it can be helpful to work at a bit level. It’s particularly common when working with microcontrollers: because of the limited processing power and memory, we want to have every bit working for us. This is particularly the case when we are communicating with or between microcontrollers, and bandwidth is at premium.

First lets have a little refresh on bits and bytes:

When we define a variable in Arduino, it designates a location in memory, with a set number of bytes. An int normally has two bytes, which is 16 bits.

int a = 6; // binary: 0000000000000110

In binary, the least significant byte is at the far right. The most significant bit is the far right, and for a signed variable like an int, it indicates if it’s negative or positive.

int a = -6; // binary: 1000000000000110

When we are interested in working on a binary level, it's sometimes helpful to use hexadecimal values, which are a bit like an intermediary between binary and decimal.

When we look at it this way, we see that in a 2-byte integer, we could for example store an RGBA colour value (Red, Green, Blue, Alpha). This could be really helpful if we say wanted to send colour values from a computer to an Arduino in the form of integers. This is principle faster than sending 4 values independently. In the next section, we will see how it’s done.

Bit Shifting Operators

The bit shifting operators are as follows:


Note, that we are using unsigned numbers here to keep things simple, refer to the Arduino reference page if you need to work with signed numbers.

Shift right:

unsigned int a = 32356;  // binary: 0111111001100100
unsigned int b = a>>8    // binary: 0000000001111110

Shift left:

unsigned int a = 32356;  // binary: 0111111001100100
unsigned int b = a<<8    // binary: 0110010000000000

In both the above cases, some of the bits have been shifted into oblivion, and 0s have filled the new spaces

If you want, you can also set values in c++ as hexadecimal or binary. The three variables below all have exactly the same value:

unsigned int RGBAvalue1 = #FF00FF16 
unsigned int RGBAvalue2 = B11111111000000001111111100010101; 
unsigned int RGBAvalue3 = 4278255382;

Putting it to use

So we can move bits around, but how do we extract sets of values out of one variable? One solution is to bracket the values we need into smaller variables with a specific length.

Here we have our colour values stored as binary in one variable:

11111111000000001111111100000000

11111111 00000000 11111111 00000000

red | green | blue | alpha

Each block is 8 bits or one byte. So we will use the byte variable chop off and keep the last 8 bits:

        unsigned int RGBAvalue = #FF00FF16 // binary: 11111111000000001111111100010101
        byte ALPHA = RGBAvalue; // binary: 00010101

We can repeat this process, in combination with the shift right operator to extract all the values:

       // In reality, we might get the RGBAvalue value from serial or BLE
        unsigned int RGBAvalue = #FF00FF16 // binary: 11111111000000001111111100010101
        byte RED =  RGBAvalue >> 24; // binary: 11111111
        byte GREEN = RGBAvalue >> 16; // binary: 00000000
        byte BLUE = RGBAvalue >> 8; // binary: 11111111
        byte ALPHA = RGBAvalue; // binary: 00010101

P5js / javascript code

But how do will combine the values to start with, before we seperate them on the Arduino? Here we are assuming that you want to do that on your computer, in a P5js web application that might use serial, BLE, or wifi to communicate with Arduino.

        const buffer = new ArrayBuffer(4); // create a 4 byte buffer to store values
		const view = new DataView(buffer); // dataview allows reading and writing without having to care about the platform's endianness.
		view.setUint8(0, Red);
		view.setUint8(1, Green);
		view.setUint8(2, Blue);
		view.setUint8(3, Alpha);
		let bufferToSend = view.getUint32();