Sitemap
the-curious-circuit

Join me as I learn electronics one project at a time — from blinking LEDs and Arduino to PCBs, embedded systems, and robotics. Every experiment includes code, explanations, mistakes, and lessons learned.

Thinking Like a Microcontroller: Bits, Bytes, Hexadecimal, Registers, Bitwise Operators, & Bitmasking

5 min readAug 5, 2026

--

Introduction

Every electronic device around you — your phone, keyboard, smartwatch, gaming controller, or microwave — is powered by a tiny computer called a microcontroller.

Unlike a desktop computer, a microcontroller interacts directly with the physical world. It turns LEDs on and off, reads buttons, drives motors, communicates with sensors, and responds to external events in real time.

To do that efficiently, it doesn’t think in terms of LEDs and buttons.

It thinks in bits.

Learning embedded programming means learning to think like the microcontroller itself.

In this blog post, I’ll write about:

  • Bits and Bytes
  • Binary and Hexadecimal
  • Registers
  • Reading and Writing Ports
  • Bitwise Operators
  • Bitmasking
  • Real-world examples

Bits and Bytes

A bit is the smallest unit of information a computer can store.

A bit has only two possible values:

0 = OFF
1 = ON

You can think of a bit as a light switch.

  • OFF → 0
  • ON → 1

Eight bits grouped together form a byte.

0 1 0 1 1 0 0 1

Almost every register inside the ATmega328P (the chip used on the Arduino Uno) is 8 bits wide, meaning it stores one byte.

The 8421 Rule

Every group of four bits (called a nibble) represents a number.

Each position has a value.

Example:

1010

Using the 8421 rule:

8 + 2 = 10

Decimal 10 is represented by A in hexadecimal.

Another example:

1101

8 + 4 + 1 = 13

Decimal 13 becomes D.

Binary and Hexadecimal

Writing long binary numbers quickly becomes difficult.

Instead of writing

11110000

we write

0xF0

The prefix 0x tells us the number is hexadecimal.

To convert binary to hexadecimal:

  1. Split the binary into groups of four bits.
  2. Convert each group using the 8421 rule.

Example:

10101101

↓

1010 1101

↓

A D

↓

0xAD

Converting back is just as easy.

0x5C

↓

5 = 0101

C = 1100

↓

01011100

Registers

A register is a very small storage location inside the microcontroller.

Each register in my Arduino usually stores 8 bits.

Example:

PORTD

00000000

Each bit corresponds to one Arduino pin.

If

PORTD = 00001000

only D3 is HIGH.

If

PORTD = 11111111

every pin is HIGH.

PORTx

The PORT register controls output voltage.

PORTD = 10101010

This produces:

  • D7 HIGH
  • D6 LOW
  • D5 HIGH
  • D4 LOW
  • D3 HIGH
  • D2 LOW
  • D1 HIGH
  • D0 LOW

PINx

The PIN register lets you read the current voltage on the pins.

Get Shivangsh Roy’s stories in your inbox

Join Medium for free to get updates from this writer.

Example:

byte value = PIND;

Suppose:

PIND = 10000101

This means:

  • D7 HIGH
  • D2 HIGH
  • D0 HIGH

Reading and Writing Entire Ports

Instead of reading one pin at a time:

digitalRead(2);
digitalRead(3);
digitalRead(4);

you can read all eight pins together:

byte inputs = PIND;

Likewise, instead of calling multiple digitalWrite() functions, you can write all eight output pins in one operation:

PORTD = 0xAA;

This immediately sets the pattern:

10101010

Direct register access is much faster than repeatedly calling Arduino library functions.

Bitwise Operators

Registers contain multiple bits, but often we only want to modify one or two without disturbing the rest.

Bitwise operators make this possible.

OR ( | ) — Set Bits

PORTD |= (1 << 3);

Turns D3 HIGH while leaving every other pin unchanged.

AND ( & ) — Read or Clear Bits

Reading a pin:

if (PIND & (1 << 5))
D5 is HIGH

Clearing a pin:

PORTD &= ~(1 << 3);

Turns D3 LOW without affecting any other output.

NOT ( ~ )

Flips every bit.

10100101

↓

01011010

Often used when creating masks.

Shift Operators

1 << 5

produces

00100000

Instead of memorizing binary numbers, programmers simply shift a single 1 into the correct position.

Bitmasking

A bitmask is simply a pattern of bits used to select or modify certain bits in a register.

Example:

PORTD |= (1 << 7) | (1 << 2);

This creates the mask:

10000100

Only D7 and D2 become HIGH.

To clear them:

PORTD &= ~((1 << 7) | (1 << 2));

Bitmasking allows us to manipulate individual pins while leaving every other pin unchanged.

Experiment : Bit-Banging

In this very simple circuit, I used a LED, 220 Ohm resistor, and an Arduino. In my code, I wrote a function called BitBang, which took a byte as its parameter, and split it into bits. If the bit was 1, I turned the state of the pin high, and if the bit was low, I turned it to 0. This resulted in the LED being switched on when the bit was 1, and off when the bit was 0. The graph displayed on the oscilloscope represents the value of each bit(High for 1, low for 0). The unique characteristic of my project is the perfect square waves, which are formed because the byte I am using is 0xAA, or 10101010 in binary. The bits are alternating between 0 and 1, so the signals are alternating between low and high. The square waves are equal, but 1 square wave is not because once the BitBang function completes, there is a delay before it is called again.

Link to the code

Press enter or click to view image in full size

Where Are These Concepts Used?

Once you begin building more advanced electronics projects, you’ll see these techniques everywhere.

Examples include:

  • LED matrices
  • Seven-segment displays
  • Rotary encoders
  • Keypad scanning
  • SPI communication
  • I²C communication
  • UART serial communication
  • Motor drivers
  • Robotics
  • IR remote receivers
  • Digital sensors
  • High-speed data acquisition

Whenever speed, precision, or direct hardware control is important, programmers use registers and bitwise operations instead of high-level functions.

Final Thoughts

Learning Arduino begins with blinking an LED.

Learning embedded systems begins when you ask:

“What is actually happening inside the microcontroller?”

Understanding bits, bytes, hexadecimal, registers, bitwise operators, and bitmasking completely changes the way you write code.

Instead of treating the Arduino like a black box, you begin speaking the language of the hardware itself.

And once you can think in bits, you’re no longer just programming an Arduino — you are programming the microcontroller.

Link to my other articles on learning electronics and embedded systems

--

--

Written by Shivangsh Roy

My name is Shivangsh Roy. I am 13 years old and love soccer, math, physics, and electronics.

Published in the-curious-circuit

Join me as I learn electronics one project at a time — from blinking LEDs and Arduino to PCBs, embedded systems, and robotics. Every experiment includes code, explanations, mistakes, and lessons learned.