← Back to Embedded C series
🔌
Basics
Basics · Prereq: lesson 2

03. Bit Operations & Register Control (set·clear·toggle)

Driving hardware ultimately means turning specific register bits on·off·reading them — while never touching the other bits (a neighbor may control a different pin). We learn the bit operators (& | ^ ~ << >>) and the three golden idioms set(|=)·clear(&= ~)·toggle(^=), plus test(>> &), with PC gcc. These idioms are reused verbatim for 8051·STM32 register control from lesson 6.

bitwisemasksetcleartoggleregister
Duration
~1–1.5 hours
Level
📊 Beginner
Prerequisite
🎯 Lesson 2
OUTCOME
Use the bit mask (1u<<n) and set/clear/toggle/test idioms to control exactly one bit while preserving the rest — the foundation of all register control.

What you'll learn

  • 1Explain the six bit operators (& | ^ ~ << >>)
  • 2Build a bit mask (1u<<n) to target a bit
  • 3set(|=)·clear(&= ~)·toggle(^=)·test(>> &) a single bit
  • 4Understand read-modify-write that preserves other bits
  • 5Operate multiple bits at once with a mask

Introduction

"GPIO pin 3 High", "clear the timer flag", "wait until the UART TX-complete bit is 1" — all manipulate a single bit inside one register. This lesson treats an 8-bit variable as a "port register" and practices the bit idioms with no board.

Key concepts

1) The six bit operators

OpNameUse
&ANDclear/test bits (masking)
|ORset bits
^XORflip bits (toggle)
~NOTinvert a mask
<<left shiftmake masks, ×2ⁿ
>>right shiftextract bits, ÷2ⁿ
⚠️

& | ^ are bitwise; && || are logical (true/false). Using && for bit work gives entirely different results.

2) Bit mask and the golden idioms

A mask has only bit n set: `(1u << n)`. The key is changing one bit while preserving the rest (read-modify-write).

ActionCodeWhy
set (to 1)reg |= (1u<<n);OR 1 → only that bit 1
clear (to 0)reg &= ~(1u<<n);AND 0 → only that bit 0
togglereg ^= (1u<<n);XOR 1 → flip that bit

The ~ (NOT) is the heart of clear: `~(1u<<n)` is 0 only at n and 1 elsewhere, so AND clears n and preserves the rest.

3) Reading a bit (test)

c
if ((reg >> n) & 1u) { ... }   /* exactly 0/1 — safe */
if (reg & (1u << n))  { ... }   /* masking: 0 or (1<<n) → truthy */

Core example

Treat an 8-bit variable as an "LED port" and split the idioms into functions (unit-testable without hardware).

c
#include <stdio.h>
#include <stdint.h>
#define BIT(n) (1u << (n))

static uint8_t set_bit(uint8_t r, unsigned n)    { return (uint8_t)(r |  BIT(n)); }
static uint8_t clear_bit(uint8_t r, unsigned n)  { return (uint8_t)(r & ~BIT(n)); }
static uint8_t toggle_bit(uint8_t r, unsigned n) { return (uint8_t)(r ^  BIT(n)); }
static int     test_bit(uint8_t r, unsigned n)   { return (int)((r >> n) & 1u); }

int main(void)
{
    uint8_t reg = 0x00;
    reg = set_bit(reg, 0);
    reg = set_bit(reg, 7);     /* 1000 0001 */
    reg = clear_bit(reg, 0);   /* 1000 0000 */
    printf("0x%02X bit7=%d\n", reg, test_bit(reg, 7));  /* 0x80 bit7=1 */
    return 0;
}

Common mistakes

Q. I cleared one bit with reg &= (1u<<n); and lost all the others.

A. clear needs the inverted mask. (1u<<n) has only that bit set, so AND wipes everything else to 0. The correct form is reg &= ~(1u << n); — ~ makes "0 at n, 1 elsewhere".

Q. if (reg & (1u<<7) == 1) is always false.

A. ① == binds tighter than &, so (1u<<7)==1 (false=0) is computed first → add parentheses. ② reg & (1u<<7) is 0x80 when true, never == 1. Use if ((reg >> 7) & 1u).

Q. A big shift like 1 << 31 misbehaves.

A. 1 is an int; shifting into the sign bit is undefined. Always start masks with the unsigned literal 1u (or 1UL). On a 32-bit register, 1u << 31 is safe.

Summary

  • A bit mask is (1u << n) — only bit n set
  • set is |=, clear is &= ~, toggle is ^= — the three register-control idioms
  • Don't drop clear's ~ or the shift's 1u (unsigned literal)
  • Read-modify-write changes one bit while preserving the rest
  • Reading a bit with (reg >> n) & 1u gives exactly 0/1

Exercises

  1. Build a mask that sets bit2·bit5 at once and apply it
  2. Write count_on() that counts the set bits in a register
  3. Show in code that toggling the same bit twice returns to the original
Example code / lecture materials

All lecture materials and example code (with homework and answers) are openly available on GitHub.

View on GitHub ↗