Binary is a base-2 numbering system where each digit (bit) represents a power of two, using only 0s and 1s to denote off/on states in digital circuits. When you figure out binary numbers for hardware, you are directly translating physical voltage levels (High/Low) into the logical instructions your microcontroller executes. Getting this wrong changes a real circuit by addressing the wrong I2C sensor, shorting a GPIO pin via a bad bitmask, or setting a DMX lighting fixture to the wrong channel. Most makers commonly confuse raw binary (base-2) with hexadecimal (base-16) shorthand, or they trip over Most Significant Bit (MSB) versus Least Significant Bit (LSB) ordering when shifting data out to peripheral chips.
The Core Mechanism: Powers of Two on the Workbench
To figure out binary numbers, you must map each physical pin or bit position to a specific power of two. Think of an 8-bit binary number like a row of eight light switches on a wall, where the rightmost switch controls a 1-watt bulb, the next controls a 2-watt bulb, the next a 4-watt bulb, and so on, up to a 128-watt bulb on the far left. To get a specific total wattage (decimal value), you flip only the switches (1s) that sum to your target, leaving the rest off (0s).
Suppose you are wiring a TI SN74HC595 shift register to control eight LEDs. You want to turn on alternating LEDs: Q0, Q2, Q4, and Q6. You need to figure out the exact binary byte to send over SPI from your ESP32 or Arduino.
- Q0 (LSB): Weight = 1. State = ON (1). Value = 1
- Q1: Weight = 2. State = OFF (0). Value = 0
- Q2: Weight = 4. State = ON (1). Value = 4
- Q3: Weight = 8. State = OFF (0). Value = 0
- Q4: Weight = 16. State = ON (1). Value = 16
- Q5: Weight = 32. State = OFF (0). Value = 0
- Q6: Weight = 64. State = ON (1). Value = 64
- Q7 (MSB): Weight = 128. State = OFF (0). Value = 0
Summing the ON values: 1 + 4 + 16 + 64 = 85.
In your code, you will send the decimal value 85, which the compiler reads as the binary sequence 01010101.
Where You Meet Binary in Physical Circuits
Abstract math becomes physical reality the moment you wire up addressable hardware. Here is where base-2 calculations dictate whether your circuit functions or fails.
1. I2C Hardware Addressing
Many I2C peripherals use physical pins to set their bus address. Take the NXP PCF8574 I/O expander. It has a base 7-bit address of 0x20 (binary 0100000). It features three address pins: A0, A1, and A2. If you wire A0 to VCC (1), A1 to GND (0), and A2 to VCC (1), your hardware binary offset is 101 (decimal 5). You add this to the base address: 0x20 + 0x05 = 0x25. If you cannot figure out this binary offset, your I2C scanner will fail to find the chip.
2. DMX512 DIP Switches
Stage lighting and DIY fog machines often use DMX512, which relies on a 10-position DIP switch to set the starting channel. Switch 1 represents a weight of 1, Switch 2 is 2, Switch 3 is 4, up to Switch 9 representing 256. (Switch 10 is reserved for test modes). If your fixture needs to start on DMX channel 137, you must figure out the binary breakdown: 128 (Switch 8) + 8 (Switch 4) + 1 (Switch 1) = 137. You flip switches 1, 4, and 8 to the ON position.
3. Direct Port Manipulation (GPIO Bitmasks)
When standard digitalWrite() functions are too slow on an ATmega328P (Arduino Uno), you write directly to the PORT registers. PORTB controls pins 8 through 13. If you want to set pins 8 and 9 as outputs without disturbing pins 10-13, you write to the DDRB register using a binary bitmask: DDRB = 0b00000011;. The two 1s on the right correspond to the two lowest pins on that port.
Decision Tree: Choosing the Right Numeric Format in Code
Makers often freeze when deciding whether to type a value in binary, hex, or decimal. Use this decision path to pick the exact literal format for your C++ or MicroPython code.
| Scenario | Condition / Goal | Concrete Pick (Use This Format) |
|---|---|---|
| Setting hardware bitmasks (e.g., DDRB, PORTB) | You need to visually map 1s and 0s to specific physical pins. | Binary Literal: 0b11001010 |
| Configuring I2C / SPI addresses | Datasheets list addresses in base-16; you are matching a hex table. | Hexadecimal: 0x38 |
| Setting PWM or AnalogWrite levels | You are dealing with a human-readable scale (0-255 or 0-1023). | Decimal: 127 |
| Pushing RGB color data to WS2812B LEDs | Colors are universally documented in 24-bit hex triplets. | Hexadecimal: 0xFF0000 |
| Sending a specific byte pattern to a shift register | You need alternating bits or a precise serial sequence. | Binary Literal: 0b10101010 |
0b prefix for binary and 0x for hex. If you just type 10, the compiler assumes decimal ten. If you type 010 with a leading zero, older C compilers will interpret it as octal (base-8), resulting in a decimal value of 8 and causing mysterious hardware bugs.
Common Pitfalls: MSB vs LSB and Bit Shifting
The most frequent cause of reversed LED patterns or corrupted serial data is confusing bit significance and transmission order.
- MSB (Most Significant Bit): The bit with the highest mathematical weight (e.g., the 128 position in an 8-bit byte). In standard notation, it is written on the far left.
- LSB (Least Significant Bit): The bit with the lowest weight (the 1 position). Written on the far right.
0b10000001 over UART, the receiving device reads the 1 on the right first, completely inverting your expected bit sequence unless you account for it in software.
When using the Arduino shiftOut() function, you must explicitly declare the order: shiftOut(dataPin, clockPin, MSBFIRST, 85);. If your physical wiring expects the LSB to hit the first LED in the chain, passing MSBFIRST will light your LEDs in reverse order.
FAQ: Quick Binary Fixes for the Workbench
How do I quickly figure out a binary number without a calculator?
Use the subtraction method. Start with the largest power of two that fits into your decimal number. For 137, the largest is 128. Subtract 128 from 137, leaving 9. The largest power of two that fits into 9 is 8. Subtract 8, leaving 1. The largest power for 1 is 1. Your active bits are 128, 8, and 1. Write a 1 in those columns and a 0 in all others: 10001001.
Why did my I2C scanner show 0x48 when my DIP switches are set to binary 001?
You are confusing the 7-bit address with the 8-bit bus byte. Many I2C scanners display the 7-bit address shifted left by one bit to make room for the Read/Write flag. If your hardware binary offset is 001 (decimal 1) added to a base of 0x20, your true 7-bit address is 0x21. Shifted left by one bit (multiplied by 2) for the bus byte, it becomes 0x42. Always check whether your scanner tool reports 7-bit or 8-bit addresses.
What is the absolute maximum number an 8-bit binary sequence can hold?
An 8-bit unsigned integer (a standard byte in Arduino C++) maxes out at 11111111 in binary. Summing all weights (128+64+32+16+8+4+2+1) yields exactly 255. If you attempt to store 256 in an 8-bit register, it will overflow and roll back to 0, a common bug when incrementing PWM counters or DMX channels.






