Binary to BCD conversion is the process of translating a pure binary number into Binary-Coded Decimal format, where each individual decimal digit is represented by its own separate 4-bit binary nibble. When you design digital circuits or write embedded firmware, the way a microcontroller counts (base-2) rarely matches how a human reads a display or a clock (base-10). Bridging this gap requires a translation layer, and BCD is the industry-standard method for keeping digital logic aligned with human-readable decimal outputs.
The Core Concept: Pure Binary vs. BCD
To understand the conversion, you must first separate pure binary from BCD. In pure binary, every bit in a register contributes to a single, continuous base-2 value. An 8-bit register can hold values from 0 to 255. The positional weight of the bits doubles as you move left (1, 2, 4, 8, 16, 32, 64, 128).
BCD abandons this continuous weighting. Instead, it treats the number as a string of independent decimal digits. Each decimal digit (0 through 9) is encoded into its own 4-bit nibble. Because a 4-bit nibble can technically hold values from 0 to 15, BCD simply ignores the states from 10 to 15.
The Common Confusion: Makers and students frequently confuse BCD with standard hexadecimal. Hexadecimal uses all 16 states of a 4-bit nibble (0-9, plus A-F for 10-15). BCD strictly forbids the states 1010 through 1111. If you probe a BCD data bus with a logic analyzer and see a nibble reading 1100 (decimal 12), it is not a valid BCD digit; it is an error state or a corrupted transmission.
Worked Numeric Example: Translating Decimal 156
Let's look at a concrete numeric example to see how the translation shifts the bit requirements. We will convert the decimal number 156 into both pure binary and BCD.
| Format | Representation | Bit Width | How it is derived |
|---|---|---|---|
| Decimal | 156 | N/A | Base-10 human readable value |
| Pure Binary | 10011100 |
8 bits | 128 + 16 + 8 + 4 = 156 |
| BCD | 0001 0101 0110 |
12 bits | Digit 1 (0001), Digit 5 (0101), Digit 6 (0110) |
Notice the trade-off. Pure binary is highly memory-efficient, packing 156 into just 8 bits. BCD requires 12 bits (three 4-bit nibbles) to represent the same value. You are sacrificing memory density in exchange for trivial decoding. To display '156' on three 7-segment displays using pure binary, the microcontroller must perform division by 100, modulo 100, division by 10, and modulo 10. With BCD, the microcontroller simply shifts each 4-bit nibble directly to its corresponding display driver.
Where You Meet Binary to BCD in Practice
You will encounter binary to BCD translation requirements across several distinct areas of electrical and electronic design:
- Real-Time Clocks (RTCs): Integrated circuits like the Maxim/Analog Devices DS3231 store time and date registers in BCD. Updating seconds from 59 to 00 and rolling over the minutes is trivial in BCD—you just reset the nibble and carry a 1 to the next nibble. In pure binary, this requires a modulo-60 operation.
- 7-Segment Display Drivers: Classic logic ICs like the Texas Instruments SN74LS47 or the CD4511 are BCD-to-7-segment decoders. They expect a 4-bit BCD input on pins A, B, C, and D, and they handle the internal logic to illuminate the correct LED segments for digits 0-9.
- Digital Multimeters (DMMs): The analog-to-digital converters inside bench and handheld multimeters (like the ICL7106) natively output BCD. This allows the meter to drive the LCD segments directly without an intermediate microcontroller.
- PLC Counters and Timers: Industrial Programmable Logic Controllers often use BCD thumbwheel switches for operator inputs. The PLC reads the 4-bit BCD lines directly to set timer presets, ensuring the operator's physical dial matches the internal logic state without software scaling.
Implementing the Conversion: Hardware vs. Firmware
Depending on your system architecture, you will handle binary to BCD conversion either in silicon or in software.
Hardware Implementation: If you are building a purely logic-based circuit without a microcontroller, you use dedicated converter ICs. The 74LS184 is a classic binary-to-BCD converter. It operates using a shift-register architecture. You load your pure binary number into the IC, pulse the clock, and the chip shifts the bits through internal add-3 logic networks, outputting valid BCD nibbles on the parallel output pins.
Firmware Implementation: If you are using an Arduino, ESP32, or STM32, you handle the conversion in C/C++. The standard algorithm for this is the Double Dabble algorithm. It works by shifting the binary number left one bit at a time. Before each shift, the algorithm checks every BCD nibble; if a nibble is 5 or greater, it adds 3 to that nibble. This pre-compensation ensures that when the bits shift into the next decimal weight, they carry over correctly into base-10 rather than base-16. While modern 32-bit ARM Cortex-M microcontrollers can execute integer division fast enough that BCD conversion is rarely a bottleneck, Double Dabble remains the most elegant, cycle-efficient method for bare-metal firmware engineers.
Frequently Asked Questions
Why do Real Time Clocks (RTCs) use BCD instead of pure binary?
RTCs use BCD because timekeeping is inherently base-10 and base-60, not base-2. When a clock increments from 09 seconds to 10 seconds, a BCD register simply rolls the lower nibble from 1001 to 0000 and increments the upper nibble from 0000 to 0001. If the RTC stored time in pure binary, the silicon would require a hardware divider to calculate modulo-60 for every single tick of the 32.768 kHz crystal, which wastes power and die area. BCD allows the RTC to handle decimal rollovers using simple, low-power nibble resets.
What happens if a microcontroller sends an invalid BCD state (10-15) to a 7-segment decoder?
The behavior depends entirely on the specific decoder IC. If you send 1010 (decimal 10) to a standard 74LS47 BCD-to-7-segment decoder, the datasheet specifies that it will output a specific, often nonsensical pattern (like a lowercase 'h' or a blank display, depending on the exact logic family and manufacturer). Some modern decoders will simply blank the display (turn off all segments) to indicate an error, while older CMOS chips might output random segment combinations that look like corrupted letters. Always mask your binary data to ensure it never exceeds 1001 before sending it to a BCD decoder.
How do I convert binary to BCD in Arduino or ESP32 C++ code?
While you can use the Double Dabble algorithm for bitwise efficiency, the most practical approach in modern Arduino/ESP32 C++ is to use standard integer math, as 32-bit processors handle division in a single clock cycle. You can extract BCD nibbles using division and modulo operators: byte tens = (value / 10) % 10; and byte ones = value % 10;. You then pack them into a single byte if your receiving hardware expects packed BCD: byte packedBCD = (tens << 4) | ones;. This packed format is exactly what I2C RTCs like the DS3231 expect when you write to their time registers.
Is BCD the same as ASCII numeric encoding?
No, they are fundamentally different encoding schemes. BCD represents numbers using raw 4-bit binary nibbles (e.g., the digit '5' is 0101). ASCII is a 7-bit or 8-bit character encoding standard used for text transmission. In ASCII, the character '5' is represented by the hex value 0x35 (binary 00110101). You will frequently need to convert BCD to ASCII when sending sensor readings from a microcontroller to a serial terminal or an LCD character display, which is done simply by adding 0x30 (the ASCII offset for '0') to your unpacked BCD nibble.






