0
A decoder is the fastest way to turn a few microcontroller pins into many device selects. In this post, you'll learn how decoders work, which type fits your project, and how to wire a 74HC138 to control eight peripherals from just three Arduino pins.
A decoder takes a binary number on its input pins and activates exactly one of its output pins. If you have three input pins, you can represent eight different binary numbers (000 through 111). A 3-to-8 decoder reads those three pins and turns on exactly one of eight outputs — output 0 for 000, output 1 for 001, all the way up to output 7 for 111.
That's it. No clock needed, no memory, no software. It's pure combinational logic: the outputs change immediately when the inputs change.
Here's the scenario. Last month, a maker was building an environmental monitoring station around an Arduino Nano. He needed to read eight separate I2C sensors, but they all had the same factory address. He was out of pins and out of ideas. The fix was a 74HC138 3-to-8 decoder. Three Arduino digital pins fed the decoder's inputs. The decoder's eight outputs became eight individual chip-select lines. By changing the three-bit pattern on the Arduino, he selected which sensor was active at any moment. Problem solved with $0.50 worth of silicon.
A decoder is not an encoder. An encoder does the opposite — it takes multiple inputs and produces a binary code. A decoder is also not a multiplexer. A multiplexer selects one of many inputs and routes it to a single output. A decoder selects one of many outputs and activates it.
You only need to know three types. The rest are specialized variants of these.
This is the type in the Arduino example. A 3-to-8 decoder like the 74HC138 is the most common. It takes a 3-bit binary input and activates one of eight outputs. The 74HC138 also has three enable pins — you can cascade multiple chips to decode larger addresses. Two 74HC138s plus one extra address line give you a 4-to-16 decoder.
There are smaller variants. A 2-to-4 decoder is useful when you only need four outputs. A 4-to-16 decoder like the 74HC154 is available if you need more. The logic is identical; only the pin count changes.
These drive numeric displays. BCD stands for Binary Coded Decimal — a 4-bit code representing digits 0-9. A decoder like the CD4511 takes those four bits and lights up the correct segments on a standard seven-segment LED display. Without the decoder, you'd need seven microcontroller pins and a lookup table in software. With it, you need four pins and zero code.
The CD4511 also has a latch input. You can set the four BCD bits, pulse the latch, and the display holds that digit even while the input lines change. That's useful when you're driving multiple digits through a single decoder using multiplexing.
These live inside every memory system. When your CPU requests data from a specific memory address, an address decoder figures out which memory chip contains that address and enables only that chip. The rest stay idle. This is how a 32-bit processor can address gigabytes of memory using thousands of individual chips — the decoder routes each request to the right place.
Modern microcontrollers have address decoders built into their memory controllers. You don't see them, but they're there. If you ever work with external SRAM or flash on an embedded system, you'll configure the chip-select logic — which is just setting up an address decoder.
The part number matters. Here's what the suffixes actually mean.
74LS series runs at 5V only. It's TTL logic — the inputs expect TTL voltage levels (0.8V low, 2.0V high). 74HC runs at 2V to 6V and uses CMOS voltage levels. If your microcontroller is 3.3V — most modern Arduinos, ESP32, STM32 — you need 74HC, not 74LS. Feeding 3.3V logic into a 74LS input is unreliable because 3.3V is barely above the 2.0V TTL threshold.
74LS is slow and power-hungry by modern standards. Propagation delay is around 8 ns per gate, and it draws milliamps of static current. 74HC is faster (6-7 ns) and draws almost no static current — CMOS only uses power when switching. 74AHC is even faster (3.5 ns) and still low power. For most hobby projects, 74HC is the sweet spot. Only use 74LS if you're repairing vintage equipment or interfacing with other TTL chips.
Standard decoders like the 74HC138 have push-pull outputs — they actively drive high or low. That's what you want for chip-select lines. Some variants have open-drain outputs, which only pull low and need external pull-up resistors to go high. Open-drain is useful for wired-OR connections but unnecessary for most decoder applications.
The 74HC138 has three enable pins: two active-low and one active-high. All three must be in the correct state for the decoder to work. This lets you cascade chips easily — connect the extra address line to one chip's active-high enable and the inverted address line to the other chip's active-high enable. Now the same three input bits select one of sixteen outputs instead of eight.
Here's how the environmental monitoring station actually worked.
The Arduino Nano had eight identical temperature sensors, all hardwired to I2C address 0x48. Connecting them all to the same bus would cause an address collision — the sensors would respond simultaneously and corrupt the data.
The solution was to put each sensor on its own I2C bus and use the decoder to select which bus was active. In practice, a simpler approach is even better: keep all sensors on one physical I2C bus, but use the decoder to control each sensor's address pin or shutdown pin. Three Arduino pins (D9, D10, D11) connected to the decoder's A, B, C inputs. The decoder's eight outputs (Y0-Y7) connected to the shutdown pins of eight sensors. Only the sensor whose shutdown line was high powered up and responded on the bus. The rest were electrically silent.
The Arduino code was simple:
void selectSensor(int n) {
digitalWrite(9, n & 1);
digitalWrite(10, (n >> 1) & 1);
digitalWrite(11, (n >> 2) & 1);
}
Call selectSensor(3) and only sensor 3 powers up. Read it. Call selectSensor(7) and only sensor 7 powers up. Read it. No address conflicts, no extra buses, no complex software.
Decoders are simple, but they fail in predictable ways.
If you leave an enable pin unconnected on a CMOS chip, it picks up noise from the air and randomly enables or disables the decoder. The outputs flicker. The circuit behaves unpredictably. Always tie unused enable pins to a defined logic level. If you're using a single 74HC138, tie both active-low enables to ground and the active-high enable to VCC.
When cascading decoders, if your address logic has a bug, both chips can be enabled simultaneously. Two outputs go low at the same time, and if those outputs drive the same bus or select two memory chips, you get a collision. Current spikes, corrupted data, possible chip damage.
Fix: Verify your enable wiring with a truth table before powering up. If both chips have their active-high enable connected to the same address line, invert one of them. Only one chip should ever be enabled at a time.
When multiple input bits change simultaneously, they don't all change at exactly the same instant. If you're going from 011 to 100, the bits might momentarily pass through 010 or 000 depending on propagation delays. The decoder sees those intermediate states and briefly activates the wrong output. That's a glitch.
Fix: If glitches matter — for example, when driving a clock or latch — add a small RC filter on the output or use a registered decoder that latches the inputs on a clock edge. For chip-select lines that just enable a slow I2C sensor, glitches usually don't matter because the sensor needs milliseconds to power up anyway.
1. A decoder turns n input bits into 2ⁿ individual outputs. Three pins become eight device selects.
2. The three types you'll use are binary-to-line, BCD-to-seven-segment, and address decoders.
3. For 3.3V microcontrollers, use 74HC, not 74LS. TTL and CMOS voltage levels are not compatible.
4. Always tie unused enable pins to a defined level. Floating CMOS inputs cause random behavior.
5. When cascading decoders, ensure only one chip is ever enabled. Use inverted enable lines to prevent collisions.
Decoders are one of those components that seem unnecessary until you need one. Then they solve a problem that would otherwise require a bigger microcontroller, a more complex PCB, or a pile of shift registers. The 74HC138 in particular is so cheap and versatile that it belongs in every electronics toolkit.
If you've used a decoder in an interesting way — or hit a problem I didn't cover here — let me know. I'm particularly curious about unusual applications beyond the standard address-decoding and display-driving scenarios.