The binary number system is a base-2 mathematical framework that represents all numerical values using only two digits, 0 and 1, where each position signifies a successive power of two. When you write digitalWrite(LED_BUILTIN, HIGH) in Arduino, you are abstracting a binary 1 into a physical voltage. But when you drop down to bare-metal register manipulation, configure a motor driver, or debug a corrupted SPI bus, that abstraction vanishes. This binary number system tutorial skips the academic fluff and focuses on how base-2 math directly dictates hardware behavior, logic thresholds, and memory states in modern embedded systems.
The Core Mechanics: Base-2 Weights and Register Mapping
In base-10 (decimal), each column represents a power of 10 (ones, tens, hundreds). In base-2, each column represents a power of 2. The rightmost bit is the Least Significant Bit (LSB) and represents $2^0$ (1). Moving left, the weights double: 2, 4, 8, 16, 32, 64, 128. An 8-bit binary number (one byte) can represent $2^8$ distinct values, ranging from 0 to 255.
11111111). To represent 256, you must overflow into a 9th bit or a secondary register.
Microcontroller datasheets rarely list raw binary; they use hexadecimal (base-16) as a shorthand. However, the physical silicon only understands binary high/low states. Here is a reference table mapping common binary bit-masks to their decimal and hex equivalents, which you will constantly encounter when configuring hardware registers.
| Binary (8-Bit) | Hexadecimal | Decimal | Hardware Application Example |
|---|---|---|---|
00000001 |
0x01 |
1 | Enable Bit 0 (e.g., I2C EN bit in a control register) |
00000010 |
0x02 |
2 | Enable Bit 1 (e.g., SPI Clock Phase select) |
00000100 |
0x04 |
4 | Enable Bit 2 (e.g., GPIO Pin 2 output mask) |
10000000 |
0x80 |
128 | Set MSB High (e.g., Triggering a software reset bit) |
10101010 |
0xAA |
170 | Alternating bit pattern (used for bus calibration/testing) |
11111111 |
0xFF |
255 | All bits high (e.g., setting all Port pins to OUTPUT) |
Worked Numeric Example: Decoding an I2C Payload
Suppose your logic analyzer captures an 8-bit payload from a temperature sensor: 10110101. What is the actual decimal value?
- Bit 7 (1): $1 \times 128 = 128$
- Bit 6 (0): $0 \times 64 = 0$
- Bit 5 (1): $1 \times 32 = 32$
- Bit 4 (1): $1 \times 16 = 16$
- Bit 3 (0): $0 \times 8 = 0$
- Bit 2 (1): $1 \times 4 = 4$
- Bit 1 (0): $0 \times 2 = 0$
- Bit 0 (1): $1 \times 1 = 1$
Sum: $128 + 32 + 16 + 4 + 1 = 181$. In hexadecimal, this is 0xB5. If the sensor datasheet specifies a 0.5°C scaling factor, this binary string represents 90.5°C.
0x0001 (1) into 0x0100 (256).Where You Meet Binary in Practical Electronics
You interact with binary states constantly, even if your IDE hides the math. Here is where base-2 logic physically manifests on your workbench:
1. Bare-Metal GPIO Registers
When you need to toggle a pin on an ESP32 or STM32 without the overhead of digitalWrite(), you write directly to the memory-mapped GPIO register. To set GPIO 5 high without altering the states of GPIO 4 or 6, you use a bitwise OR operation with a binary mask. You shift a binary 1 left by 5 positions (1 << 5), yielding 00100000 (decimal 32, hex 0x20). Writing this mask to the GPIO_OUT_W1TS_REG (Write 1 to Set) flips only that specific physical pin high.
2. DIP Switches on Motor Drivers
Look at the side of a TB6600 stepper motor driver or an A4988 carrier board. Those tiny sliding switches are physical binary inputs. A 3-switch block for microstepping (e.g., ON-ON-OFF) is literally a 3-bit binary string (110) read by the driver's internal logic gates to determine if the motor should step at 1/4, 1/8, or 1/16 resolution.
3. Logic Analyzer Bus Decoding
When debugging an I2C or SPI bus with a Saleae or DSLogic analyzer, the raw traces are just voltage transitions. The software groups these 8 physical channels into a single binary byte, translating the physical voltage highs and lows into the NXP I2C specification payload format. If your pull-up resistors are too weak, the logic analyzer will show undefined states (neither a clean binary 1 nor 0), resulting in corrupted hex outputs.
What Binary Changes in a Real Circuit Design
Understanding binary isn't just about software math; it dictates physical component selection and circuit tolerances. Here is what base-2 logic changes in your hardware design.
Voltage Thresholds and Noise Margins
A binary '0' is not strictly 0.00V, and a '1' is not strictly 5.00V. In standard 5V TTL logic, a binary '0' is guaranteed to be read correctly as long as the voltage is below 0.8V. A binary '1' is guaranteed as long as it is above 2.0V. The gap between 0.8V and 2.0V is the undefined transition zone. If your PCB trace is too long, or you lack proper decoupling capacitors, electromagnetic interference (EMI) can push a floating input pin to 1.4V. The microcontroller's internal Schmitt trigger won't know if that's a binary 0 or 1, causing ghost interrupts.
ADC Resolution and Step Size
An Analog-to-Digital Converter (ADC) translates continuous analog voltage into discrete binary steps. The number of bits dictates your physical measurement precision. As detailed in standard digital electronics principles, a 10-bit ADC (like on the ATmega328P) yields $2^{10}$ (1024) steps. A 12-bit ADC (like on the ESP32) yields $2^{12}$ (4096) steps.
Common Confusions: Binary, Hex, and Gray Code
Makers frequently conflate binary with related concepts. Clarifying these distinctions prevents critical errors in sensor integration and bus debugging.
Hexadecimal vs. Binary
Hexadecimal (base-16) is not a different physical state; it is purely a human-readable compression of binary. Hardware does not know what "0xFF" is; it only sees eight high voltage rails (11111111). We use hex because reading a 32-bit memory address in binary (1100101011110001...) is prone to human miscounting, whereas 0xCAF1 is easily parsed. Always remember: when calculating bit-masks, convert hex to binary first, apply your logical AND/OR operations, and convert back.
Standard Binary vs. Gray Code
In standard binary, transitioning from decimal 3 (011) to decimal 4 (100) requires three bits to flip simultaneously. In a physical rotary encoder, mechanical bounce and slight sensor misalignment mean the microcontroller might read 111 or 000 during the transition, causing massive position errors. Gray code solves this by ensuring only one single bit changes between any adjacent values (e.g., 3 is 010, 4 is 110). If you are wiring an absolute encoder to a PLC or microcontroller, you must configure the input register to decode Gray code, not standard binary.
Bit Rate vs. Baud Rate
While binary defines the state (1 or 0), bit rate and baud rate define the speed. Bit rate is the number of binary 1s and 0s transmitted per second. Baud rate is the number of signal transitions per second. In simple UART serial, they are identical. But in advanced modulation schemes, one signal transition can encode multiple binary bits simultaneously.
Frequently Asked Questions
Why do we count from Bit 0 instead of Bit 1?
In computer science and digital logic, the LSB is Bit 0 because it represents $2^0$ (which equals 1). Counting from zero aligns the bit index directly with the exponent of the base, making bitwise shift operations (1 << n) mathematically consistent.
What happens if I send a 9-bit binary value to an 8-bit register?
The 9th bit (the MSB) will be truncated and silently discarded. If you try to write decimal 256 (100000000) to an 8-bit register, the lower 8 bits are all zeros, and the register will store 0. Always apply a bitwise AND mask (value & 0xFF) to prevent unexpected overflows.
Can I use binary math for PWM duty cycles?
Yes. An 8-bit PWM timer (like Timer0 on an AVR) counts from 0 to 255 in binary. Setting the compare register to 127 (01111111) yields an approximately 50% duty cycle. The hardware comparator flips the output pin low the exact moment the binary counter matches your register value.






