
Extend Arduino Inputs and Outputs
Many Arduino projects hit a wall. You run out of pins. You need more buttons. You want more LEDs. But your Arduino only has so many digital ports. That’s where smart chips come in.
Instead of using 16 pins for 8 buttons and 8 LEDs, you can do it with just 6. That’s a huge saving. It frees up space. It cuts down wiring. It makes your build cleaner.
This guide shows you exactly how. You’ll learn to use two powerful chips: the 74HC165 shift register and the 74HC4051 analog multiplexer. Together, they turn a tiny Arduino into a powerful controller.
Why Use Shift Registers and Multiplexers?
You don’t need more Arduino boards. You don’t need a Raspberry Pi. You just need two small chips.
Shift registers let you read many inputs through one wire. Multiplexers let you control many outputs using one PWM pin. Both save pins. Both cut cost. Both make projects smarter.
Most beginners think they need 8 pins for 8 buttons. That’s wrong. With the 74HC165, you use only 3 pins. Same for LEDs. With the 74HC4051, you control 8 LEDs with just 1 PWM pin and 3 address lines.
This method works for any microcontroller. Not just Arduino. Not just Uno. It works on Nano, Mega, Pico, even ESP32. The logic stays the same.
What Is the 74HC165 Shift Register?
The 74HC165 is a parallel-in, serial-out shift register. That means it grabs 8 inputs at once. Then sends them out one by one.
Connect 8 buttons to its input pins. Each button is a digital signal: high or low. When you trigger the chip, it reads all 8 at the same time.
Then, it sends those 8 bits out through a single data pin. Your Arduino reads them as a byte. One read. Eight buttons.
This chip uses only 3 Arduino pins: clock, load, and data. That’s it. No extra resistors. No complex code. Just simple timing.
It’s cheap. You can buy 10 for under $2. It’s reliable. It’s used in keyboards, game controllers, and industrial systems.
How the 74HC165 Reads 8 Buttons
First, connect each button to one of the 74HC165’s input pins. Use pull-down resistors. Or use the Arduino’s internal pull-ups.
Then, connect three Arduino pins to the chip:
– CLK (Clock) → Arduino pin 2
– LOAD → Arduino pin 3
– Q7 (Data Out) → Arduino pin 4
When you press a button, it pulls the input high. The chip stores that state.
To read the buttons, you send a low pulse to the LOAD pin. That tells the chip to lock in the current button states.
Then, you send 8 clock pulses. Each pulse moves one bit out. You read each bit with digitalRead().
Put all 8 bits together. You get one byte. Each bit tells you if a button is pressed (1) or not (0).
This happens fast. In under 1 millisecond. Your project feels instant. No lag. No delay.
What Is the 74HC4051 Multiplexer?
The 74HC4051 is an analog multiplexer. It acts like a rotary switch. You pick one of eight paths. Then you connect it to a common output.
In this project, we use it to control LEDs. Not to read sensors. Not for analog signals. Just for turning LEDs on and off.
You connect 8 LEDs to its 8 output channels. You connect the common pin to your PWM output on Arduino.
Now, you control which LED gets power. You don’t need 8 PWM pins. You need just one.
The chip uses three address pins (S0, S1, S2). Each combination of high and low selects a different LED.
For example:
– S0=0, S1=0, S2=0 → LED 1
– S0=1, S1=0, S2=0 → LED 2
– S0=0, S1=1, S2=0 → LED 3
And so on. All the way to LED 8.
That’s 3 pins for 8 outputs. You save 5 pins. That’s huge.
How the 74HC4051 Controls 8 LEDs
Connect the common output (COM) to Arduino pin 9. That’s your PWM pin.
Connect S0, S1, S2 to Arduino pins 5, 6, and 7. These set which LED you pick.
Each LED needs a current-limiting resistor. Use 220 ohms. Connect one end to the LED. Connect the other to the 74HC4051 channel.
Now, in your code, you loop through each LED. For each one:
– Set S0, S1, S2 to match the LED number
– Check if the button for that LED is pressed
– If pressed, toggle the LED state with XOR
– Set PWM value to 255 (on) or 0 (off)
That’s it. You don’t need 8 transistors. You don’t need 8 resistors per LED. Just one PWM pin and three control lines.
XOR Logic: Toggle LEDs With One Line
Here’s the smart part. You don’t use if-else. You don’t use state variables. You use XOR.
XOR means “exclusive OR.” If both inputs are the same, output is 0. If they’re different, output is 1.
So if the LED is OFF (0) and you press the button (1), then 0 XOR 1 = 1. The LED turns ON.
If the LED is ON (1) and you press again, 1 XOR 1 = 0. The LED turns OFF.
You don’t need to track if it’s on or off. The chip remembers. The button press flips it. Simple. Clean. Elegant.
In code, it looks like this:
buttonStates[i] ^= 1; // Toggle LED state
That one line replaces a whole if-statement. It’s faster. It uses less memory. It’s perfect for embedded systems.
Pin Connections: Full Wiring Guide
74HC165 Shift Register Connections
Here’s how to wire the 74HC165 to your Arduino:
| 74HC165 Pin | Arduino Pin | Function |
|---|---|---|
| 1 (CLK) | 2 | Clock input |
| 2 (PL) | 3 | Parallel Load |
| 9 (Q7) | 4 | Data output |
| 16 (VCC) | 5V | Power |
| 8 (GND) | GND | Ground |
| 3–8 (A–H) | Buttons to GND | 8 button inputs |
Each button connects from the chip’s input to ground. Use a 10k resistor from each input to 5V. That keeps the signal high when not pressed.
74HC4051 Multiplexer Connections
| 74HC4051 Pin | Arduino Pin | Function |
|---|---|---|
| 1 (Y0) | LED 1 | Output to LED |
| 2 (Y1) | LED 2 | Output to LED |
| 3 (Y2) | LED 3 | Output to LED |
| 4 (Y3) | LED 4 | Output to LED |
| 5 (Y4) | LED 5 | Output to LED |
| 6 (Y5) | LED 6 | Output to LED |
| 7 (Y6) | LED 7 | Output to LED |
| 15 (Y7) | LED 8 | Output to LED |
| 16 (VCC) | 5V | Power |
| 8 (GND) | GND | Ground |
| 10 (Z) | D9 | PWM output |
| 11 (S0) | D5 | Address bit 0 |
| 12 (S1) | D6 | Address bit 1 |
| 13 (S2) | D7 | Address bit 2 |
Each LED gets a 220-ohm resistor between the chip and the LED’s anode. The cathode goes to ground.
Full Arduino Code Explained
Here’s the complete code. It runs in a loop. It reads buttons. It updates LEDs. It’s short. It’s clean. It’s efficient.
// Pin definitions
const int clkPin = 2; // 74HC165 clock
const int loadPin = 3; // 74HC165 load
const int dataPin = 4; // 74HC165 data out
const int s0 = 5; // 74HC4051 address bit 0
const int s1 = 6; // 74HC4051 address bit 1
const int s2 = 7; // 74HC4051 address bit 2
const int pwmPin = 9; // PWM output for LED brightness
// Button and LED states
byte buttonStates = 0;
byte ledStates = 0;
void setup() {
pinMode(clkPin, OUTPUT);
pinMode(loadPin, OUTPUT);
pinMode(dataPin, INPUT);
pinMode(s0, OUTPUT);
pinMode(s1, OUTPUT);
pinMode(s2, OUTPUT);
pinMode(pwmPin, OUTPUT);
digitalWrite(loadPin, HIGH); // Start with load high
analogWrite(pwmPin, 0); // Start with LEDs off
}
void loop() {
// Read all 8 buttons at once
digitalWrite(loadPin, LOW); // Load current button states
delayMicroseconds(1);
digitalWrite(loadPin, HIGH); // Stop loading
buttonStates = 0;
for (int i = 0; i < 8; i++) {
bitWrite(buttonStates, i, digitalRead(dataPin));
digitalWrite(clkPin, HIGH);
delayMicroseconds(1);
digitalWrite(clkPin, LOW);
}
// Update each LED based on button press
for (int i = 0; i < 8; i++) {
// Set multiplexer to select LED i
digitalWrite(s0, i & 1);
digitalWrite(s1, (i >> 1) & 1);
digitalWrite(s2, (i >> 2) & 1);
// Toggle LED if button is pressed
if (bitRead(buttonStates, i)) {
ledStates ^= (1 << i); // XOR toggle
}
// Set LED brightness: ON or OFF
if (ledStates & (1 << i)) {
analogWrite(pwmPin, 255); // Full brightness
} else {
analogWrite(pwmPin, 0); // Off
}
delay(1); // Small delay for stability
}
delay(20); // Slow loop to avoid flicker
}
This code does everything. It reads buttons. It toggles LEDs. It sets brightness. It uses no extra libraries.
It runs on any Arduino. Uno, Nano, Mega. Even a clone. It doesn’t need a fancy board.
How This Saves Arduino Pins
Without these chips, you’d need 16 pins. 8 for buttons. 8 for LEDs.
With the 74HC165 and 74HC4051, you only need 6 pins.
Here’s the breakdown:
- 3 pins for the shift register (CLK, LOAD, DATA)
- 3 pins for the multiplexer (S0, S1, S2)
- 1 PWM pin shared for all LEDs (D9)
That’s 7 pins total. Wait — the PWM pin is also used. So 7 pins.
But you still need power and ground. Those aren’t counted as GPIO. So you save 9 pins.
That’s 56% fewer pins used. You can now add sensors, displays, or radios. You’re not stuck.
Real-World Uses for This Setup
This isn’t just a lab trick. It’s used in real products.
Think of a home automation panel. You have 8 buttons. You want 8 status lights. You don’t want 16 wires running to your controller.
Or a MIDI controller. 8 knobs. 8 buttons. You need to send data to a computer. This setup cuts the wiring in half.
Even robotics. You need 8 motor controls. You have a small microcontroller. This lets you drive 8 motors with 3 pins.
It’s perfect for DIY arcade cabinets. Retro game controllers. Custom input devices.
Any project where space, cost, or pin count matters.
Buy the Right Parts — No Guessing
You don’t need expensive parts. You don’t need original Arduino boards.
Elegoo boards work great. They’re cheaper. They’re compatible. They use the same IDE.
Here’s what you need:
- Arduino Uno Rev3 or ELEGOO UNO R3
- 40 PCS 20 CM Breadboard Jumper Wires
- HiLetgo 5pcs USB to Serial CH340 Module (for programming clones)
- 74HC165 Shift Register (buy 5 — they’re cheap)
- 74HC4051 Multiplexer (buy 3)
- 8x 220-ohm resistors
- 8x LEDs (any color)
- 8x push buttons (tactile switches)
These parts cost under $15 total. You can build this project for less than a coffee.
Common Mistakes and How to Fix Them
Many people get this wrong. Here are the top 3 errors:
Mistake 1: No Pull-Up Resistors
If buttons don’t work, check the inputs. Without pull-ups, the signal floats. You get random readings.
Solution: Add 10k resistors from each button input to 5V. Or enable internal pull-ups in code.
Mistake 2: Wrong PWM Pin
Not all Arduino pins support PWM. D9, D10, D11 work on Uno. D3, D5, D6, D9, D10, D11 work on Nano.
Solution: Check your board’s pinout. Use a PWM-capable pin. Or use a transistor to boost the signal.
Mistake 3: Too Fast Loop
If LEDs flicker, your loop runs too fast. The multiplexer switches faster than the LED can respond.
Solution: Add a 1ms delay after setting each LED. Add a 20ms delay at the end of the loop.
Upgrade This Project: Add More
You can chain shift registers. Connect two 74HC165 chips. Now you read 16 buttons with 3 pins.
You can chain multiplexers. Use two 74HC4051 chips. Control 16 LEDs with 1 PWM pin and 4 address lines.
Add a display. Use I2C. Only 2 pins needed. Show which buttons are pressed.
Add a buzzer. Play a tone when a button is pressed. Make it interactive.
Connect it to Bluetooth. Use HC-05. Send button states to your phone.
This project is a foundation. It’s not the end. It’s the start.
Test Your Build — Debug Step by Step
Don’t plug everything in at once. Test in parts.
First, test the shift register alone. Upload a simple sketch. Print buttonStates to Serial Monitor. Press buttons. See if bits change.
Then, test the multiplexer. Manually set S0, S1, S2. Watch which LED lights up. Use a multimeter to check voltage.
Finally, combine them. Add the XOR toggle. Watch the LEDs respond.
If it fails, check wiring. Double-check pin numbers. Use a breadboard with good contacts.
Final Thoughts: Smarter, Not Harder
You don’t need a bigger Arduino. You don’t need a Raspberry Pi. You don’t need expensive shields.
You just need to think smarter.
Chips like the 74HC165 and 74HC4051 are tools. They’re not scary. They’re simple. They’re cheap.
Use them to extend your projects. Save pins. Save money. Save space.
This method works for beginners. It works for experts. It works for classrooms. It works for makers.
Now you know how to control 8 inputs and 8 outputs with just 6 pins.
Go build something cool.
FAQ: Your Questions Answered
Can I use this with ESP32?
Yes. ESP32 has more pins, but this still saves them. Use any digital pins for CLK, LOAD, DATA, S0, S1, S2.
Do I need transistors for the LEDs?
No. The 74HC4051 can handle 20mA per channel. Most LEDs use 10–15mA. So it’s fine. No extra parts needed.
Can I use analog buttons?
Yes. Change the 74HC4051 to read analog values. Use it as a multiplexer for sensors. Read 8 potentiometers with one analog pin.
Why not use a GPIO expander like PCF8574?
PCF8574 uses I2C. It’s great. But it needs pull-up resistors. It’s slower. And it costs more. This method is faster. Cheaper. Simpler.
Is this project safe for kids?
Absolutely. Low voltage. No high power. No soldering needed. Use a breadboard. Supervise young makers. It’s a perfect STEM project.
Ready to Build? Get Started Today
You have everything you need. The code. The wiring. The parts list.
Start small. Build one LED and one button. Make it work. Then add the rest.
This project teaches you real electronics. Not just coding. Real hardware. Real problem solving.
And best of all — you can build it in an afternoon.
Proteus • library folder — Find Proteus library folder easily
Arduino • Elegoo — Arduino vs Elegoo: the real difference in 2025 (which to buy)
Arduino-compatible • board selection — Which Arduino-compatible board is right for you
Happy building.











Leave a Reply