Binary is a base-2 numbering system that uses only two digits, 0 and 1, to represent all numerical values and logical states in digital electronics. In a physical circuit, binary dictates how a microcontroller maps physical voltage thresholds (e.g., 0V for a logical '0' and 3.3V for a logical '1') to hardware operations, directly controlling GPIO pin outputs, serial communication timing, and memory addressing. Makers frequently confuse binary math (the numerical base-2 system) with binary logic families (the physical voltage thresholds like TTL vs. CMOS), or they mistakenly treat hexadecimal as a separate physical system rather than just a human-readable shorthand for binary.
The Core Math: Translating Base-10 to Base-2
Unlike the decimal (base-10) system you use daily, which relies on powers of 10 (ones, tens, hundreds), binary relies on powers of 2. Each position in a binary number, called a bit, represents a specific weight. When a bit is '1', you add its weight to the total; when it is '0', you ignore it. This direct mapping to powers of 2 is exactly why computer memory and microcontroller registers are sized in multiples of 8, 16, 32, and 64 bits.
| Bit Position | Standard Name | Weight (Base-10) | Power of 2 | Max Cumulative Value |
|---|---|---|---|---|
| Bit 7 | MSB (Most Significant Bit) | 128 | 2^7 | 255 |
| Bit 6 | 64 | 2^6 | 127 | |
| Bit 5 | 32 | 2^5 | 63 | |
| Bit 4 | 16 | 2^4 | 31 | |
| Bit 3 | 8 | 2^3 | 15 | |
| Bit 2 | 4 | 2^2 | 7 | |
| Bit 1 | 2 | 2^1 | 3 | |
| Bit 0 | LSB (Least Significant Bit) | 1 | 2^0 | 1 |
Worked Numeric Example: Decimal to Binary
Let’s convert the decimal number 173 into an 8-bit binary sequence. We subtract the largest possible power of 2 from our target number, moving left to right:
- 128: 173 - 128 = 45. (Bit 7 = 1)
- 64: 45 is smaller than 64. (Bit 6 = 0)
- 32: 45 - 32 = 13. (Bit 5 = 1)
- 16: 13 is smaller than 16. (Bit 4 = 0)
- 8: 13 - 8 = 5. (Bit 3 = 1)
- 4: 5 - 4 = 1. (Bit 2 = 1)
- 2: 1 is smaller than 2. (Bit 1 = 0)
- 1: 1 - 1 = 0. (Bit 0 = 1)
Reading the bits from MSB to LSB, the decimal value 173 is written in binary as 10101101. For a deeper dive into the foundational logic gates that process these bits, refer to the All About Circuits Digital Logic textbook.
Where You Meet Binary in Practice
Binary isn’t just abstract math; it is the physical reality of how your workbench components operate. Here is where you will directly interact with binary states in a typical maker project:
1. GPIO Pin Control and Hardware Registers
When you write digitalWrite(13, HIGH) on an Arduino Uno, you aren’t just flipping a conceptual switch. The microcontroller’s C++ abstraction layer is literally modifying a specific bit inside a hardware memory register (like PORTB on the ATmega328P). Setting that bit to '1' connects the physical pin to the VCC rail (5V) through a MOSFET; setting it to '0' connects it to GND (0V).
2. Shift Registers (e.g., 74HC595)
If you need to control 16 LEDs but only have 3 free pins on your ESP32, you use a shift register. You clock in an 8-bit binary number (like 10100001) one bit at a time via the SPI or I2C bus. The shift register stores this binary pattern in its internal latches and drives the corresponding physical output pins high or low simultaneously.
3. Analog-to-Digital Conversion (ADC)
When reading a sensor, a 12-bit ADC on an ESP32-S3 maps the continuous analog voltage (0V to 3.3V) into a discrete binary number. A reading of 0V yields 000000000000 (decimal 0), while 3.3V yields 111111111111 (decimal 4095). The Espressif ESP32 ADC Documentation details how non-linearities at the extreme ends of this binary range often require software calibration.
Binary vs. Hexadecimal: Clearing Up the Confusion
The most common point of confusion for beginners is the relationship between binary and hexadecimal (hex). Hexadecimal (base-16) is not a different physical layer or a separate mathematical reality in the chip. It is simply a human-readable compression of binary, created because reading long strings of 1s and 0s is prone to errors.
Because 16 is a power of 2 ($2^4$), exactly four binary bits (a "nibble") map perfectly to one hexadecimal digit. This makes hex invaluable for defining I2C memory addresses, RGB color codes, and bitwise masks in code.
| Criteria | Binary (Base-2) | Hexadecimal (Base-16) | Decimal (Base-10) |
|---|---|---|---|
| Digits Used | 0, 1 | 0-9, A-F | 0-9 |
| Bits Represented | 1 bit per digit | 4 bits per digit | ~3.32 bits per digit |
| Value 255 Representation | 11111111 |
0xFF |
255 |
| Primary Use Case | Hardware registers, bitwise logic masks, pin states | Memory addresses, I2C registers, MAC addresses | Human math, sensor outputs, PWM duty cycles |
| Code Prefix | 0b (e.g., 0b1010) |
0x (e.g., 0x0A) |
None (e.g., 10) |
When you write code to manipulate specific hardware features, you use binary logic (bitwise operations). For example, if you want to turn on Bit 3 of a register without disturbing the other 7 bits, you use a binary OR mask: REG = REG | (1 << 3). The compiler handles the hex or decimal translation, but the physical silicon only ever sees the binary 1s and 0s.
FAQ: Troubleshooting Binary and Logic Levels
Q: Why is my ESP32 reading random 1s and 0s on a GPIO pin when nothing is connected?
A: This is a "floating pin" issue. An unconnected microcontroller pin acts like an antenna, picking up electromagnetic interference (EMI) from your bench, mains wiring, or nearby RF signals. The internal high-impedance CMOS input buffer interprets these tiny induced voltage fluctuations as random binary 1s and 0s. The fix is to use a 10kΩ pull-down resistor (to force a default binary 0) or a pull-up resistor (to force a default binary 1), or enable the internal pull-up/down resistors in your code.
Q: How do I safely interface a 5V binary sensor with a 3.3V microcontroller?
A: You must translate the voltage thresholds. The safest and most robust method for high-speed signals is a dedicated logic level shifter IC (like the TXB0108 or BSS138 MOSFET-based bidirectional shifters). For slow, unidirectional signals (like a simple push-button or PIR sensor output), a simple voltage divider using a 2kΩ and 3.3kΩ resistor network will safely drop the 5V binary '1' down to a safe ~3.0V binary '1' for the ESP32. For a comprehensive guide on voltage thresholds, review the SparkFun Logic Levels Tutorial.
Q: Does a binary '0' always mean exactly 0.0 Volts?
A: No. In real-world circuits, there is voltage drop and noise. Microcontroller datasheets define specific thresholds: $V_{IL}$ (Input Low Voltage) and $V_{IH}$ (Input High Voltage). For a standard 3.3V ESP32, any voltage measured below 0.8V is guaranteed to be read as a binary '0', and any voltage above 2.4V is guaranteed to be read as a binary '1'. The voltage range between 0.8V and 2.4V is the "indeterminate zone" where the binary state is undefined and the chip may read it as either, or oscillate rapidly.






