MicroPython Bitwise Operators

Contents

Introduction

Operators are an essential part of just about any computing language ever devised and MicroPython is of no exception. The MicroPython operators can be broadly classified into eight groups:

  1. Arithmetic
    - , + , * , / , % , ** , //
  2. Assignment
    = , augmented assignments e.g. +=
  3. Comparison
    == , != , > , < , >= , <=
  4. Logical
    and , or , not
  5. Identity
    is , is not
  6. Membership
    in , not in
  7. Bitwise
    & , ! , ^ , ~ , << , >>
  8. Unpacking Operators
    * , **

Bitwise Operations

Computers store all kinds of information as a stream of binary digits called bits. Whether working with text, images, or videos, they all boil down to ones and zeros. MicroPython's bitwise operators allows manipulation of these individual bits of data at the most granular level.[1]

Bitwise operators can be used to implement algorithms such as compression, encryption, and error detection as well as to control physical devices such as microcontrollers. Real world devices (sensors, specific IC chips, motor controllers and so on) are connected to microcontrollers via their ports. The ports are usually 8 or 16 bits wide. These bitwise operators can be used to read or write an individual bit on a port.

Most programmers will import third party code libraries that do this for them where the controller's ports are presented as a simple abstraction in the form of a class with easy to use methods that allow high level manipulation down to the bit level. However it is still useful to know about these operators and how they work.

The Bitwise Operators

Python provides six bitwise operators that are now common in many programming languages. MicroPython supports all six of the Python bitwise operators.

When operating at the binary (base-2) level it is often useful to use integers written in a direct binary format. This is easily accomplished by prefixing with 0b to indicate that the proceeding value is in binary format.

The bin() function can be used to convert an integer in any base form to the binary format. The bin() function can also be used inside the print() function to force the output to the binary representation. The following examples illustrates these points.

Example 1

# Demonstrate the bin() function

X = 0b10101010
print('X (decimal):', X)
print('X (binary):', bin(X), '\n')

Y = bin(150)
print('Y (binary):', Y)
          
Output:

X (decimal): 170
X (binary): 0b10101010 

Y (binary): 0b10010110
          

Note that the print() function converts an integer to decimal (base-10) by default unless the bin() function is explicitly used.

The six MicroPython bitwise operators are sumarised in Table 1.

Table 1: MicroPython Bitwise operators
Operator Meaning Example
& Bitwise AND a & b
! Bitwise OR a & b
^ Bitwise XOR a ^ b
~ Bitwise NOT ~a
<< Bitwise left shift a << b
>> Bitwise right shift a >> b

Bitwise AND (&)

The bitwise AND operator & performs logical conjunction on the corresponding bits of its operands. For each pair of bits occupying the same position in the two numbers, it returns a one (1) only when both bits are also one (1).

Python bitwise AND example
FIG 1 - MicroPython Bitwise AND Operation

Bitwise OR (|)

The bitwise OR operator | performs logical disjunction. For each corresponding pair of bits, it returns a one (1) if at least one of them is a one (1).

Python bitwise OR example
FIG 2 - MicroPython Bitwise OR Operation

Bitwise XOR (^)

The name XOR stands for “exclusive or” since it performs exclusive disjunction on the bit pairs. In other words, every bit pair must contain opposing bit values to produce a one (1).

Python bitwise XOR example
FIG 3 - MicroPython Bitwise XOR Operation

Bitwise NOT (~)

The last of the bitwise logical operators is the bitwise NOT operator ~, which expects just one argument, making it the only unary bitwise operator. It performs logical negation on a given number by flipping all of its bits i.e. a one (1) becomes a zero (0) and a zero (0) becomes a one (1).

Python bitwise NOT example
FIG 4 - MicroPython Bitwise NOT Operation

As shown in FIG 4, the Python bitwise NOT ~ operator can give confusing results. This is a direct cause of MicroPython's mechanism used for coding negative numbers. If a bitwise AND (&) operation is applied to the result of the bitwise NOT operation then the expected value will be returned as shown in the code block in FIG 4. Applying the mask 0b11111111 converts the signed integer to the (unsigned) bit pattern expected.

Bitwise Left Shift (<<)

The bitwise left shift operator << moves the bits of its first operand to the left by the number of places specified in its second operand. It also takes care of inserting enough zero bits to fill the gap that arises on the right edge of the new bit pattern. The example below shows pictorially the result of the left shift operation: 0b10010110 << 2

Python bitwise Left Shift example
FIG 5 - MicroPython Bitwise Left Shift Operation

When dealing with microcontroller 8-bit ports it is usually desirable to convert the left shift result to 8-bits i.e. dropping bits from the left hand side. This is easily achieved using a mask; simply by applying the bitwise AND operation & 0b11111111 to the shift result.

Bitwise Right Shift (>>)

The bitwise right shift operator >> moves the bits of its first operand to the right by the number of places specified in its second operand. The right most bits get dropped and zero bits are inserted to fill the gap that arises on the left edge of the new bit pattern. The example below shows pictorially the result of the right shift operation: 0b10010110 >> 2

Python bitwise Right Shift example
FIG 6 - MicroPython Bitwise Right Shift Operation

And this completes the discussion of Python bitwise (logical and shift) operations. While most programmers may never use these operations they are still handy to understand as they allow easy manipulation of integers down to the bit level.