Binary Coded Decimal (BCD) is a digital encoding system where each individual decimal digit (0 through 9) is represented by its own distinct four-bit binary sequence. While microcontrollers and FPGAs natively compute in pure binary or hexadecimal, humans read and set values in base-10. BCD bridges this gap, dictating how we wire digital displays, program PLC counters, and interface thumbwheel switches without requiring complex binary-to-decimal math on the fly. Think of it like a mechanical odometer in a car: each digit wheel rolls independently from 0 to 9, rather than the entire number rolling over as one massive binary count.

When you switch a design from pure binary to BCD, it fundamentally changes your hardware interface and software masking. In hardware, you can no longer feed a 4-bit counter directly into a DAC or a pure binary adder; you must route it through a BCD-to-decimal decoder or a BCD-to-7-segment driver. In software, you must mask out the six invalid states (1010 through 1111) that exist in every 4-bit nibble, or your microcontroller will interpret a mechanical switch bounce as an invalid number, crashing your math routines.

Pure Binary vs. BCD: The Core Difference

The most common mistake hobbyists and junior engineers make is confusing BCD with pure binary or hexadecimal. Pure binary treats the entire string of bits as a single mathematical value. Hexadecimal is simply a human-readable shorthand for pure binary (grouping bits into 4-bit nibbles). BCD, however, restricts each 4-bit nibble to a maximum value of 9. Any binary value from 1010 (10) to 1111 (15) is strictly illegal in standard 8421 BCD.

Decimal Value Pure Binary (8-bit) Hexadecimal BCD (8421 format)
9 0000 1001 0x09 0000 1001
15 0000 1111 0x0F 0001 0101 (Illegal in single nibble)
42 0010 1010 0x2A 0100 0010
99 0110 0011 0x63 1001 1001

Notice how decimal 42 in pure binary is 0010 1010, but in BCD it is 0100 0010. The '4' is encoded as 0100 and the '2' as 0010. This is why BCD is sometimes called '8421 code'—representing the binary weights of the four bits (8, 4, 2, 1) used to build each decimal digit.

Worked Numeric Example: Translating 8421 BCD

Let's translate a three-digit decimal number into BCD and compare it to pure binary to see the exact bit-level differences. We will use the number 459.

  1. Break into decimal digits: 4, 5, 9.
  2. Convert each digit to 4-bit binary:
    • 4 = 0100
    • 5 = 0101
    • 9 = 1001
  3. Concatenate for BCD: 0100 0101 1001 (12 bits total).

Now, let's look at pure binary for 459. The largest power of 2 that fits is 256. 459 - 256 = 203. Next is 128. 203 - 128 = 75. Next is 64. 75 - 64 = 11. Next is 8. 11 - 8 = 3. Next is 2. 3 - 2 = 1. Finally, 1. Pure binary for 459 is 1 1100 1011 (9 bits total).

The BCD representation uses 12 bits to store the same value that pure binary stores in 9 bits. This 33% memory overhead is the primary trade-off of BCD, but it is entirely worth it when the data needs to be displayed on a 7-segment LED array or read from a physical decade switch.

Where You Meet BCD in Practice

You will rarely use BCD for internal microcontroller math, but you will constantly encounter it at the edges of your system where humans interact with machines:

  • 7-Segment Displays: Chips like the Texas Instruments SN74LS47N or the CD4511BE take 4 BCD input pins and drive the 7 LEDs required to display the decimal number. They handle the complex Boolean logic of turning on segments 'a' through 'g' so your MCU doesn't have to.
  • PLC Timers and Counters: Legacy industrial HMIs and older Allen-Bradley or Omron PLCs often use BCD for preset values. If you are retrofitting a vintage machine, the thumbwheel switches on the control panel are outputting BCD, not pure binary.
  • Digital Calipers and Multimeters: Many cheap digital calipers output data over a serial protocol using BCD formatting for each digit of the measurement, making it easy to parse on an Arduino without floating-point math.
Warning: Invalid BCD States
Standard BCD decoders like the 74LS47 have specific behaviors for inputs 10 through 15. Instead of blanking the display, the 74LS47 will output bizarre, asymmetric symbols (like a lowercase 'c' or a blank 'f'). If your BCD source has floating pins or switch bounce, your display will flash these garbage characters. Always use hardware pull resistors and software debouncing to ensure the nibble never exceeds 9.

Real-World Scenario Walkthrough: The Thumbwheel Switch Bug

Here is a classic bench failure that illustrates how BCD behaves in a physical circuit.

The Setup: You are wiring an Omron A6D-4104 BCD thumbwheel switch to an Arduino Mega 2560 to set a motor run-timer. The switch has 5 pins: a Common pin, and four output pins labeled 1, 2, 4, and 8. You wire the Common pin to GND, and the four output pins directly to Arduino digital inputs 22, 23, 24, and 25.

The Numbers: You set the physical dial to '8'. In BCD, 8 is 1000. You expect the Arduino to read Pin 8 as HIGH, and Pins 1, 2, and 4 as LOW.

The Outcome: The Arduino Serial Monitor reads random values between 8 and 15. The motor timer triggers instantly or fails to start. The display shows garbage.

What Went Wrong: The Omron A6D switch is a 'make' switch. When you dial '8', it connects the '8' pin to Common (GND). But what about the '1', '2', and '4' pins? They are physically disconnected from Common. Because you wired Common to GND, the active pin is pulled to GND (LOW), but the inactive pins are left electrically floating. Without pull-up resistors, those floating pins act as antennas, picking up 60Hz EMI from your bench power supply and reading as logic HIGH. The Arduino reads 1111 (15) instead of 1000 (8).

The Fix: 1. Enable the Arduino's internal pull-up resistors in code: pinMode(22, INPUT_PULLUP); 2. Wire the Common pin on the switch to VCC (5V) instead of GND. 3. Invert the logic in software, because the active pin now pulls the input LOW. 4. Apply a bitwise mask to isolate the 4-bit nibble and reject invalid BCD states:

byte raw_val = ~PINA & 0x0F; // Read Port A, invert, mask lower 4 bits
if (raw_val > 9) {
  // Handle invalid BCD state (switch bounce or error)
  raw_val = 0; 
}

FAQ: BCD Binary Coded Decimal in Circuit Design

Does BCD waste memory compared to pure binary?
Yes. Because each 4-bit nibble can only hold values 0-9, the states 10-15 are wasted. This means BCD uses about 20% more memory than pure binary for large numbers. However, for storing user-facing settings (like a clock time or a 3-digit temperature setpoint), the memory cost is negligible, and the CPU cycles saved by avoiding binary-to-decimal division algorithms far outweigh the RAM cost.

What is the difference between BCD and ASCII?
ASCII is a 7-bit or 8-bit character encoding standard used for text. The ASCII character for the digit '5' is 0x35 (0011 0101). BCD for '5' is simply 0101. When reading serial data from a GPS module or a digital scale, you are often receiving ASCII characters that you must strip of their upper nibble (0x30) to recover the raw BCD/decimal value.

Can I use a standard binary adder chip (like the 74LS283) to add two BCD numbers?
No, not directly. If you add BCD 5 (0101) and BCD 7 (0111) using a pure binary adder, you get 1100 (12), which is an invalid BCD state. You must use a dedicated BCD adder (like the CD4008B with correction logic) or add a 'correction factor' of 6 (0110) to the sum whenever the result exceeds 9, forcing the carry bit to roll over correctly into the next decimal decade. For more on logic family corrections, see this guide on Binary Coded Decimal logic.