The Quick Answer: If you are reading an 8-bit binary byte like 11010110 (a common value when polling an I2C status register or an 8-bit ADC like the PCF8591), the direct decimal conversion is 214 (unsigned) or -42 (signed two's complement). For a simpler 4-bit nibble like 1010, the decimal value is 10.
When you are debugging embedded systems, staring at a logic analyzer trace, or parsing raw bytes from a sensor, you need to convert binary to decimal examples quickly and accurately. But unlike basic math class, the 'correct' answer on the bench depends entirely on how the microcontroller's memory is structured. Below is the exact formula, the hardware assumptions that fix your answer, and a decision path to ensure you don't misinterpret a critical sensor reading.
The Core Formula and Substituted Values
The standard positional notation formula for converting a binary integer to decimal is:
Decimal = (b_n × 2^n) + (b_{n-1} × 2^{n-1}) + ... + (b_0 × 2^0)
Let's substitute the values for our target 8-bit byte, 11010110, reading from right (Least Significant Bit, 2^0) to left (Most Significant Bit, 2^7):
- Bit 0 (0): 0 × 2^0 = 0
- Bit 1 (1): 1 × 2^1 = 2
- Bit 2 (1): 1 × 2^2 = 4
- Bit 3 (0): 0 × 2^3 = 0
- Bit 4 (1): 1 × 2^4 = 16
- Bit 5 (0): 0 × 2^5 = 0
- Bit 6 (1): 1 × 2^6 = 64
- Bit 7 (1): 1 × 2^7 = 128
Sum: 128 + 64 + 16 + 4 + 2 = 214.
To give you a sense of the surrounding data space, here is a reference table covering the ±20% range (approximately 171 to 255) around our target value. This is the exact band you'll see when monitoring a fluctuating analog sensor or a drifting temperature register.
| Binary (8-bit) | Hexadecimal | Unsigned Decimal | Signed Decimal (Two's Complement) |
|---|---|---|---|
| 10101011 | 0xAB | 171 | -85 |
| 11000000 | 0xC0 | 192 | -64 |
| 11010101 | 0xD5 | 213 | -43 |
| 11010110 | 0xD6 | 214 | -42 |
| 11010111 | 0xD7 | 215 | -41 |
| 11101000 | 0xE8 | 232 | -24 |
| 11111111 | 0xFF | 255 | -1 |
What Assumptions Fix Your Answer?
In embedded C/C++ (like Arduino or ESP-IDF), a binary sequence is just raw memory. The decimal value you get is fixed by three hardware and software assumptions:
Bench Tip: Always check the sensor datasheet's 'Data Format' section before writing your parsing code. Assuming unsigned when the sensor outputs signed data is the #1 cause of 'my temperature sensor reads 65,000 degrees' bugs.
1. Bit-Width (8-bit vs 16-bit vs 32-bit)
If 11010110 is an isolated 8-bit register, it's 214. But if it is the lower byte of a 16-bit little-endian register (common in ESP32 I2C peripherals), and the upper byte is 00000001, the combined binary is 00000001 11010110. The decimal value shifts dramatically to 470. If you treat a 16-bit register as an 8-bit variable, you silently truncate the upper byte.
2. Signed vs. Unsigned (Two's Complement)
As shown in the table above, if the Most Significant Bit (MSB) is a 1, the unsigned value is >127. However, if the hardware uses two's complement for negative numbers (standard for temperature sensors like the TMP102 or accelerometer axes), that MSB acts as a negative sign weight. The exact same binary 11010110 becomes -42.
3. Endianness
When converting multi-byte binary streams over UART or SPI, byte order matters. An ESP32 (little-endian) will read a 32-bit integer differently than a network packet (big-endian). If you don't account for endianness, your decimal conversion will yield completely scrambled values.
Decision Tree: Which Decimal Value Do You Actually Need?
Use this decision path when writing your parsing logic to terminate on the exact C++ cast or bitwise operation you need.
| What are you reading? | Condition / Check | Concrete Action / Code Implementation |
|---|---|---|
| GPIO Pin State / Bitmask | Is it a port register (e.g., PORTD)? | Cast to uint8_t. Use unsigned. (Value: 214) |
| Temperature / Acceleration | Does the datasheet specify negative ranges? | Cast to int8_t or int16_t. Use signed two's complement. (Value: -42) |
| 12-bit ADC packed in 16 bits | Are the top 4 bits padding or status flags? | Apply bitmask first: (raw & 0x0FFF), then convert. |
| Raw I2C Command Byte | Is it an instruction rather than a measurement? | Use Hexadecimal (0xD6) for readability; decimal is irrelevant. |
Default Recommendation: If you are unsure and just dumping raw memory for debugging, always cast to uint8_t (unsigned) and print in Hexadecimal. It prevents accidental sign-extension bugs when passing the value to larger integer types.
When Binary-to-Decimal Conversion is Meaningless
There are specific scenarios on the workbench where applying standard integer conversion to a binary string will give you a mathematically correct but practically useless number.
1. IEEE 754 Floating Point Data
If you read 32 bits from a high-precision sensor and the binary is 01000000010010010000111111011011, converting this via standard positional notation yields 1078523867. This is meaningless. That binary sequence is the IEEE 754 representation of the float 3.14159. You must cast the memory pointer to a float in C++, not an integer.
2. Unmasked Status Registers
According to the NXP I2C-bus specification, many devices pack multiple boolean flags into a single byte. If bit 2 is 'Data Ready' and bit 3 is 'Overcurrent', converting the whole byte to decimal (e.g., 12) tells you nothing. You must use bitwise AND operations (reg & (1 << 2)) to isolate the specific flags.
FAQ: Common Embedded Conversion Pitfalls
Why does my ESP32 print massive numbers like 4,294,967,254 when I expect a small negative decimal?
This is a classic sign-extension error. You read an 8-bit signed value (like -42) into a 32-bit unsigned integer (uint32_t). The compiler pads the upper 24 bits with 1s to preserve the negative sign in two's complement, resulting in 0xFFFFFFD6, which is 4,294,967,254 in unsigned decimal. Fix it by explicitly casting to int8_t before assigning to a larger variable.
How do I handle a 10-bit ADC value spread across two 8-bit I2C registers?
Read the MSB and LSB registers. Shift the MSB left by 8 bits, then bitwise OR it with the LSB. Finally, apply a 10-bit mask: uint16_t adc = ((msb << 8) | lsb) & 0x03FF;. Converting the raw combined binary without the mask will include garbage status bits in your decimal output.
Is there a hardware shortcut for binary-to-decimal on microcontrollers?
Microcontrollers do not natively 'think' in decimal; they operate entirely in binary logic gates. Decimal conversion only happens at the very end of the chain when you call a function like Serial.print(value, DEC), which triggers a software division loop to generate ASCII characters for your serial monitor. Keep your internal math in binary/hex, and only convert to decimal for the human-readable UI layer.






