A binary coded decimal number is a digital encoding system where each individual base-10 decimal digit (0 through 9) is represented by its own distinct four-bit binary sequence. While modern microcontrollers process data in pure binary or hexadecimal, the binary coded decimal (BCD) format remains a foundational bridge between human-readable decimal interfaces and digital logic. In a real circuit, utilizing BCD instead of pure binary drastically simplifies the hardware required to drive numeric displays and decode thumbwheel switches, though it sacrifices 38% of the potential states in a 4-bit data bus to do so. What beginners most commonly confuse BCD with is pure binary conversion, assuming a decimal value is converted to binary as a whole rather than digit-by-digit.
The BCD Lookup Table and Core Mechanics
The most common BCD encoding scheme is the 8421 code. This name is not arbitrary; it represents the positional weight of each bit in the 4-bit nibble. The Most Significant Bit (MSB) carries a weight of 8, followed by 4, 2, and 1 for the Least Significant Bit (LSB). Because we only need to represent ten digits (0-9), the binary states from 1010 (decimal 10) through 1111 (decimal 15) are strictly considered invalid or 'forbidden' states in standard BCD logic.
| Decimal Digit | BCD Nibble | Bit 3 (Wt: 8) | Bit 2 (Wt: 4) | Bit 1 (Wt: 2) | Bit 0 (Wt: 1) | Hex Equivalent |
|---|---|---|---|---|---|---|
| 0 | 0000 | 0 | 0 | 0 | 0 | 0x0 |
| 1 | 0001 | 0 | 0 | 0 | 1 | 0x1 |
| 2 | 0010 | 0 | 0 | 1 | 0 | 0x2 |
| 3 | 0011 | 0 | 0 | 1 | 1 | 0x3 |
| 4 | 0100 | 0 | 1 | 0 | 0 | 0x4 |
| 5 | 0101 | 0 | 1 | 0 | 1 | 0x5 |
| 6 | 0110 | 0 | 1 | 1 | 0 | 0x6 |
| 7 | 0111 | 0 | 1 | 1 | 1 | 0x7 |
| 8 | 1000 | 1 | 0 | 0 | 0 | 0x8 |
| 9 | 1001 | 1 | 0 | 0 | 1 | 0x9 |
| Invalid | 1010 - 1111 | States 10 through 15 are unused in standard 8421 BCD | 0xA - 0xF | |||
Think of a mechanical car odometer: each physical wheel only rolls through 0-9 before triggering the next wheel to its left to advance by one, rather than counting continuously in base-16. BCD mimics this exact mechanical behavior in digital logic.
Pure Binary vs. BCD: A Worked Numeric Example
The most frequent error hobbyists make when debugging digital logic or writing microcontroller firmware is treating a BCD byte as a pure binary integer. Let us look at a concrete numeric example using the decimal value 254.
Pure Binary Conversion
If you convert the entire decimal number 254 into standard pure binary, you perform successive division by 2. The result is an 8-bit byte: 11111110 (or 0xFE in hex). To display this on three 7-segment displays, your microcontroller would need to run a division algorithm to extract the hundreds, tens, and ones places before sending them to the display drivers.
BCD Conversion
In BCD, you do not convert the whole number. You isolate each decimal digit and convert them individually into 4-bit nibbles:
- 2 becomes 0010
- 5 becomes 0101
- 4 becomes 0100
Concatenating these yields the 12-bit BCD sequence: 0010 0101 0100. While this consumes 50% more memory/bandwidth than pure binary (12 bits vs 8 bits), the hardware implementation is trivial. You simply route each 4-bit nibble directly to its own dedicated BCD-to-7-segment decoder IC. No mathematical division is required in the silicon.
Where You Meet BCD in Practical Circuits
You will rarely write BCD arithmetic from scratch, but you will constantly interface with hardware that relies on it. Here are the three most common places BCD dictates your wiring and code on the bench.
1. Real-Time Clock (RTC) Modules via I2C
If you have ever wired a DS3231 RTC module to an Arduino or ESP32, you have used BCD. The internal timekeeping registers of the DS3231 store seconds, minutes, and hours in BCD format to prevent complex binary-to-decimal conversions inside the low-power silicon. For example, Register 0x00h (Seconds) stores the value 59 not as 0x3B (pure binary 59), but as 0x59 (BCD for 59). If you read this I2C register directly into a standard integer variable without bit-masking, your serial monitor will erroneously report 89 seconds (because 0x59 in hex equals 89 in decimal).
When writing custom I2C drivers for RTCs in C/C++, always use a conversion function to translate the BCD byte returned by the Wire library into a usable decimal integer:
byte bcdToDec(byte val) { return ( (val/16*10) + (val%16) ); }2. BCD-to-7-Segment Decoder Drivers
Legacy but highly reliable ICs like the Texas Instruments SN74LS47 (for common-anode displays) or the CD4511 (for common-cathode displays) are pure hardware BCD decoders. You wire four GPIO pins from your microcontroller to the A, B, C, and D inputs of the IC. If you send the BCD nibble 0111 (decimal 7), the IC automatically illuminates the correct LED segments. If you accidentally send an invalid BCD state (like 1100), the CD4511's internal logic detects the forbidden state and automatically blanks the display to prevent showing garbage characters.
3. Industrial Thumbwheel Switches
On industrial control panels and older CNC equipment, operators set parameters using physical BCD thumbwheel switches. Behind the plastic wheel, a set of four micro-switches or a rotary encoder outputs a hardwired 4-bit BCD code. PLCs read these 4 bits via digital inputs, guaranteeing the operator can never physically dial in an invalid hexadecimal value.
Frequently Asked Questions
Why not just use pure binary for everything in modern microcontrollers?
Inside the CPU, pure binary is indeed used for everything. However, at the edge of the system—where humans interact with machines via physical dials, switches, and numeric displays—BCD saves significant logic gate count and firmware overhead. Driving three 7-segment displays from a pure binary integer requires division and modulo operations in software, or a complex programmable logic array in hardware. BCD allows a simple, direct 1-to-1 mapping from a 4-bit bus to a single decimal digit.
What happens to the unused states (1010 to 1111) in BCD arithmetic?
In dedicated BCD adder circuits (like the 74LS83 configured for BCD), if the sum of two BCD digits exceeds 9 (1001), the circuit automatically adds 6 (0110) to the result. This skips over the six invalid states (10 through 15) and generates a carry bit to the next decimal column, ensuring the output remains a valid BCD number.
Can I use an ESP32 to read a 4-bit BCD switch directly?
Yes. Wire the four switch outputs to four consecutive GPIO pins (e.g., GPIO 4, 5, 12, and 13). Use a bitwise AND operation to mask the pins and read them as a single nibble. Just remember to implement software debouncing, as mechanical BCD switches will bounce through multiple invalid transient states before settling on the final digit.






