Bitwise operations in C

In our first lesson (/start-working-with-atmel-avr-microcontrollers/), we got acquainted with the working principle of microcontrollers. But, of course, it's not very convenient to simply write numbers in binary or hexadecimal form in registers. What if you need to change only one bit on a port, without touching the others? Change its value from 0 to 1 or vice versa? We'll answer that question a little later.

First, let's consider bitwise operations in C.

Bitwise operations can only be applied to integer types.

Types of bitwise operators:

  • & (or and),
  • | (or OR),
  • ^ (or XOR),
  • ~ (or NOT),
  • left shift,
  • right shift.
The first four operations give a result similar to mathematical logic: We compare the value of each pair of bits. As a result, we get an integer type as well. For example,
1 & 1 == 1; 
1 | 0 == 1; 
1 & 0 == 0;
0b01 | 0b11 == 0b11, etc.
The operations << - left shift and >> - right shift simply shift the bits of a number in the corresponding direction. For example:
0b010 << 1 == 0b100; 
0b010 >> 1 == 0b001;
0b00001 << 3 == 0b01000; 

0b00100 << 3 == 0b00001, etc.

Why do we need bitwise operations in C for microcontrollers?

For example, we want to make the value of the 3rd bit equal to 1, without touching the other bits. It looks like this:

PORTA |= 1 << 3;
Let's analyze. For example, the value on PORTA = 0b1010. Now, when we perform the operation 0b1010 | 0b100, we get 0b1110. Thus, we set 1 to the 3rd position regardless of the values of the other bits and the current value of the 3rd bit. To set 0, we need to do it a little differently:
PORTA &= ~(1 << 3);
We shift 1 to the 3rd position, perform a logical negation (resulting in 0b011), now, regardless of the value on PORTA, we get 0 at the 3rd position.