Binary is a base-2 numeral system that uses only two digits, 0 and 1, to represent all possible values, states, and instructions in digital electronics. In a real circuit or embedded installation, knowing how to read binary numbers allows you to decode raw hardware register states, configure precise GPIO pin masks, and troubleshoot I2C or SPI communication frames at the logic analyzer level. Beginners often confuse pure binary with Binary-Coded Decimal (BCD) or treat hexadecimal as a separate concept rather than a shorthand, leading to misconfigured microcontroller registers and failed peripheral initializations.
The Core Mechanism: Base-2 Place Values
Unlike the decimal (base-10) system where each column represents a power of 10 (ones, tens, hundreds), binary columns represent powers of 2. Think of it like a row of physical toggle switches on a breaker panel: each switch is either OFF (0) or ON (1), and the combination of all switches determines the total load.
Let us walk through a worked numeric example using an 8-bit byte commonly seen in microcontroller registers. We want to decode the binary sequence 10110101.
- Bit 7 (MSB): 1 × 27 = 128
- Bit 6: 0 × 26 = 0
- Bit 5: 1 × 25 = 32
- Bit 4: 1 × 24 = 16
- Bit 3: 0 × 23 = 0
- Bit 2: 1 × 22 = 4
- Bit 1: 0 × 21 = 0
- Bit 0 (LSB): 1 × 20 = 1
Adding the active columns together: 128 + 32 + 16 + 4 + 1 = 181. Therefore, 10110101 in binary is exactly 181 in decimal, or 0xB5 in hexadecimal.
10000000 (128) and 01000000 (64) bits. If the most significant bit (MSB) is 1 in a signed 8-bit integer (two's complement), the number is actually negative. In unsigned logic (like GPIO states), it simply means the value is 128 or higher.
Where You Meet Binary in Practice
You rarely write out long strings of 1s and 0s by hand, but you must read them constantly when interacting with hardware at the register level. Here is where binary literacy pays off on the workbench.
GPIO Pin Masking
When you need to set specific pins high on an ESP32 or Arduino without disturbing the others, you write a binary mask. If you want to turn ON Pin 2 and Pin 5, you construct a byte where only bit 2 and bit 5 are 1. Reading from right (bit 0) to left, that binary string is 00100100. In C++, you write this as 0b00100100 (decimal 36). If you accidentally read the string backward and write 0b00100100 thinking bit 0 is on the left, you will toggle the wrong pins, potentially shorting a peripheral.
I2C Addressing and the R/W Bit
The NXP I2C bus specification defines a 7-bit device address. However, on a logic analyzer, you will see 8 bits transmitted. The 8th bit (the LSB) is the Read/Write bit. If your OLED display has a 7-bit address of 0x3C (binary 0111100), the actual byte sent on the wire for a Write operation is 01111000 (0x78), and for a Read operation, it is 01111001 (0x79). Knowing how to read binary numbers lets you instantly spot why a logic analyzer shows a different address byte than your datasheet.
Hexadecimal Shorthand and Bitwise Math
Because reading a 32-bit register in pure binary (10110000111100001010101000000001) causes eye strain and transcription errors, engineers use hexadecimal (base-16). Hex groups binary into neat 4-bit nibbles.
| Decimal | 4-Bit Binary (Nibble) | Hexadecimal |
|---|---|---|
| 0 | 0000 | 0 |
| 5 | 0101 | 5 |
| 10 | 1010 | A |
| 15 | 1111 | F |
When manipulating these bits in firmware, we use bitwise operators. Understanding these is mandatory for reading datasheets like the ESP32 Technical Reference Manual.
- Bitwise AND (
&): Used for masking.10110101 & 00001111strips away the top four bits, leaving only the lower nibble (00000101). - Bitwise OR (
|): Used for setting bits.10110101 | 00000010forces bit 1 high without changing the rest. - Bitwise XOR (
^): Used for toggling.10110101 ^ 00000001flips the LSB. If it was 1, it becomes 0.
Common Pitfalls When Reading Datasheets
Even experienced makers trip over specific binary conventions in silicon datasheets.
Bit Numbering vs. Byte Ordering: In almost all microcontroller documentation, the Least Significant Bit (LSB) is designated as Bit 0, and the Most Significant Bit (MSB) is Bit 7 (for an 8-bit register) or Bit 31 (for a 32-bit register). Never assume Bit 1 is the LSB. Furthermore, when reading multi-byte data over SPI or I2C, you must check the device's endianness. A 16-bit sensor reading might transmit the MSB first (Big-Endian) or the LSB first (Little-Endian). If you read the binary stream backward, a temperature reading of 25.0°C might decode as a nonsensical value.
Active-Low Logic: Datasheets often denote pins or register bits with a bar over the name (e.g., RESET) or a trailing slash (RESET_n). In binary, a 0 triggers the action, and a 1 is the idle state. If you read a binary trace and see a 0 on an interrupt line, the device is actively signaling, not turning off.
Frequently Asked Questions
How to read binary numbers directly from an oscilloscope or logic analyzer?
When using a tool like a Saleae Logic Analyzer or a Rigol oscilloscope, you first set the trigger and sample rate (e.g., 1 MS/s for standard I2C). The software decodes the high (1) and low (0) voltage thresholds into a binary string. To read it, align your cursor with the clock edge (rising or falling, depending on the protocol). Read the logic levels from left to right as they appear on the screen, but always verify the protocol's bit-ordering specification (MSB-first vs. LSB-first) to correctly assemble the byte.
Why do microcontrollers use binary instead of decimal?
Microcontrollers use binary because their fundamental building block, the MOSFET, operates as a switch with two stable states: cut-off (high impedance/low voltage) and saturation (low impedance/high voltage). Creating a physical transistor that can reliably distinguish between 10 distinct voltage levels (for base-10 decimal) on a nanometer scale would result in massive crosstalk, thermal drift errors, and unmanageable power consumption. Binary provides maximum noise immunity; a 3.3V system only needs to distinguish between roughly 0-1.0V (Logic 0) and 2.0-3.3V (Logic 1).
How to read binary numbers when dealing with Arduino C++ code?
In Arduino C++, you can read and write binary directly using the 0b prefix. For example, byte config = 0b10100011; is perfectly valid. However, if you are reading a serial string of ASCII characters (like '1' and '0' from a text file), you must parse them. Use strtol(myString, NULL, 2) to convert a null-terminated binary string into an integer, specifying base 2. Do not use atoi(), as it assumes base 10 and will mangle your binary data.
What is the fastest mental trick to convert binary to decimal?
Do not calculate powers of 2 from scratch. Memorize the 'nibble' values: 1000 is 8, 0100 is 4, 0010 is 2, and 0001 is 1. When looking at an 8-bit byte, split it visually down the middle. If you see 1100 0101, instantly recognize the left half (1100) as 12, and the right half (0101) as 5. The left half represents multiples of 16, so 12 × 16 = 192. Add the right half (5) to get 197. This split-nibble method is significantly faster than counting individual bit positions and aligns perfectly with hexadecimal translation.
For a deeper dive into digital logic foundations, the All About Circuits digital textbook provides excellent foundational exercises on base conversions and Boolean algebra.






