Why this project?
Arduino boards run out of GPIO pins fast when you start doing LED patterns or building a control panel. The 74HC595 serial-in/parallel-out (SIPO) shift register lets you trade a few pins (data, clock, latch) for many outputs. Each chip adds 8 outputs, and by chaining IC chips you can scale well beyond 16 channels—limited mainly by signal integrity, update speed, and power.
This guide shows you how to:
Wire two 74HC595s to control 16 LEDs using only three Arduino pins
Add more chips with no code rewrite (change one number)
Use PWM on OE for global brightness
Initialize cleanly to avoid “mystery LEDs” turning on at power-up
Organize code so each LED is addressed by a single channel index (0..N-1)
Bill of Materials
Required
1 × Arduino Uno (or any 5 V-logic compatible board)
16 × LEDs
16 × 220 Ω resistors (one per LED; 180–330 Ω is typical—see Current section)
Breadboard(s) and jumper wires
Optional but recommended
2 × 0.1 µF ceramic capacitors (one per 74HC595 between VCC and GND for decoupling)
1 × External 5 V supply if you plan to light many LEDs at once
1 × Potentiometer (if you insist on analog dimming in series—not recommended)
1 × PWM-capable Arduino pin wired to OE for global brightness (recommended)
How the 74HC595 Works (Quickly)
DS (SER, pin 14): Data in (one bit per clock)
SH_CP (SRCLK, pin 11): Shift clock; on rising edge the bit on DS enters the shift register
ST_CP (RCLK, pin 12): Latch clock; rising edge copies the internal shift register to outputs Q0..Q7
Q7′ (pin 9): Serial data out; chain this to the next chip’s DS
OE (pin 13): Output enable, active low (LOW = outputs active). Tie to GND, or to a PWM pin for dimming
MR (pin 10): Master reset, active low. Keep HIGH for normal use. Pulse LOW to clear all bits
Data is clocked into the first chip; bits ripple toward the last chip. On latch, all outputs update together—zero flicker if you write quickly.
Wiring (Two Chips → 16 LEDs)
Common Power/Control
VCC (pin 16) → 5 V
GND (pin 8) → GND
0.1 µF between VCC and GND on each chip (close to the IC)
Control Lines (Arduino → both chips)
SH_CP (pin 11) → Arduino D12 (clock)
ST_CP (pin 12) → Arduino D8 (latch)
OE (pin 13) → GND (or a PWM pin like D3 for global brightness)
MR (pin 10) → 5 V (or a digital pin if you want software reset)
Serial Data & Daisy-Chain
Chip 1 DS (pin 14) → Arduino D11 (data)
Chip 1 Q7′ (pin 9) → Chip 2 DS (pin 14)
If you add a third chip: Chip 2 Q7′ → Chip 3 DS, and so on
LEDs
For each chip:
Q0..Q7 (pins 15, 1, 2, 3, 4, 5, 6, 7) → 220 Ω resistor → LED → GND
(You can reverse LED polarity if you prefer sourcing vs sinking current; the code is the same—just invert logic if needed.)
Channel Numbering (Simple Mental Model)
The chip closest to Arduino is register 0: it controls channels 0..7
The next chip is register 1: channels 8..15
With N chips, channels go 0..(8N−1)
The code below lets you call regWrite(channel, state) without caring which register or bit that is.
Power & Current: What You Can Safely Drive
Typical LED current with 220 Ω at 5 V is ~5–10 mA depending on LED color (VF).
Example (red LED): (5 V − 2.0 V) / 220 Ω ≈ 13.6 mA (often too bright; many LEDs are fine at 5 mA)
The 74HC595 can’t source/sink large current on all pins simultaneously. Keep per-pin current ≤ 8 mA and total per chip ≤ ~50 mA (check your datasheet).
If you need to drive lots of LEDs at once at higher current, use transistor arrays (e.g., ULN2803) or MOSFETs, or multiplex with 74HC595 + 74HC138 etc.
For many simultaneously-on LEDs, use a separate 5 V supply for the LED side and common GND with Arduino.
Avoid “Random LEDs on at Power-Up”
At startup, the internal register has undefined contents.
Software fix: Immediately write zeros and latch in setup()
Hardware fix: Tie MR to an Arduino pin; briefly drive LOW→HIGH after boot
No-glare boot: Hold OE HIGH (outputs off), preload zeros, then set OE LOW
Why PWM on OE Beats a Series Pot
Putting a pot in series with all LEDs changes current and can cause color mismatch and uneven brightness. Driving OE from a PWM pin keeps per-LED resistors fixed and dims everything uniformly via duty cycle. (Remember: OE is active LOW. More PWM duty = darker unless you invert it in code.)
Step-by-Step Assembly
Place the two SN74HC595N on the breadboard with power rails connected; add 0.1 µF caps per chip.
Wire Arduino D11→DS(14), D12→SH_CP(11), D8→ST_CP(12). Tie OE(13)→GND and MR(10)→5 V (or to Arduino pins as described).
Connect Chip 1 Q7′(9)→Chip 2 DS(14).
Add resistors from each Q pin to its LED, and LEDs back to GND.
Double-check power and grounds; verify no shorts.
Upload the sketch and test.
The Code (drop-in, scalable)
Change NUM_REGS to match how many 74HC595s you chained.
Use regWrite(channel, state) to set any LED.
flush() pushes the entire state array out.
Optional OE_PIN for global brightness via analogWrite.
// ===== User Configuration =====
const int DATA_PIN = 11; // DS -> 74HC595 pin 14
const int CLOCK_PIN = 12; // SH_CP-> 74HC595 pin 11
const int LATCH_PIN = 8; // ST_CP-> 74HC595 pin 12
const int MR_PIN = -1; // Tie to 5V or assign a pin (active LOW). -1 = tied HIGH.
const int OE_PIN = -1; // Tie to GND or assign a PWM pin (active LOW). -1 = tied LOW.
const int NUM_REGS = 2; // 2 chips = 16 channels; set to your chain length
// ==============================
byte regs[NUM_REGS]; // Each byte is Q0..Q7; bit 0 -> Q0, bit 7 -> Q7
inline void latch() {
digitalWrite(LATCH_PIN, LOW);
digitalWrite(LATCH_PIN, HIGH);
}
// Push regs[] to the chain (send farthest chip first)
void flush() {
digitalWrite(LATCH_PIN, LOW);
for (int i = NUM_REGS - 1; i >= 0; --i) {
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, regs[i]);
}
digitalWrite(LATCH_PIN, HIGH);
}
void clearAll() {
for (int i = 0; i < NUM_REGS; ++i) regs[i] = 0;
flush();
}
// Set one channel (0..NUM_REGS*8-1), then flush
void regWrite(int channel, bool state) {
if (channel < 0 || channel >= NUM_REGS * 8) return;
int r = channel / 8; // which register
int b = channel % 8; // which bit (0=Q0 .. 7=Q7)
bitWrite(regs[r], b, state);
flush();
}
// Optionally set all 8-bit registers at once then flush (length must be NUM_REGS)
void writeAll(const byte* values) {
for (int i = 0; i < NUM_REGS; ++i) regs[i] = values[i];
flush();
}
void setup() {
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
if (MR_PIN >= 0) {
pinMode(MR_PIN, OUTPUT);
digitalWrite(MR_PIN, HIGH); // keep not-reset (LOW would clear)
}
if (OE_PIN >= 0) {
pinMode(OE_PIN, OUTPUT);
digitalWrite(OE_PIN, LOW); // enable outputs (LOW = on)
}
// Clean startup
clearAll();
// If you wired MR to a pin and want to hard-reset at boot:
// if (MR_PIN >= 0) { digitalWrite(MR_PIN, LOW); delay(1); digitalWrite(MR_PIN, HIGH); }
// If you wired OE to a pin and want outputs disabled during init:
// if (OE_PIN >= 0) { digitalWrite(OE_PIN, HIGH); /* preload zeros */ clearAll(); digitalWrite(OE_PIN, LOW); }
}
void loop() {
const int N = NUM_REGS * 8;
// 1) Light up one-by-one
for (int i = 0; i < N; ++i) { regWrite(i, true); delay(60); }
delay(200);
for (int i = N - 1; i >= 0; --i) { regWrite(i, false); delay(40); }
delay(200);
// 2) Single "runner" back and forth
clearAll();
for (int pass = 0; pass < 2; ++pass) {
for (int i = 0; i < N; ++i) { clearAll(); regWrite(i, true); delay(40); }
for (int i = N - 1; i >= 0; --i) { clearAll(); regWrite(i, true); delay(40); }
}
// 3) Even/odd blink pattern
byte evenMask = 0b01010101; // Q0,2,4,6
byte oddMask = 0b10101010; // Q1,3,5,7
for (int k = 0; k < 6; ++k) {
for (int r = 0; r < NUM_REGS; ++r) regs[r] = (k % 2 == 0) ? evenMask : oddMask;
flush();
delay(180);
}
// 4) Global brightness sweep via OE (if connected to PWM pin)
// NOTE: OE is active LOW. We invert the duty with (255 - d).
/*
if (OE_PIN >= 0) {
for (int r = 0; r < NUM_REGS; ++r) regs[r] = 0xFF; // all on
flush();
for (int d = 0; d <= 255; d += 5) { analogWrite(OE_PIN, 255 - d); delay(8); }
for (int d = 255; d >= 0; d -= 5) { analogWrite(OE_PIN, 255 - d); delay(8); }
}
*/
}
Scaling to More LEDs
Hardware: Chain Q7′ of the last chip to DS of the new chip; share clock, latch, OE, MR, VCC, GND.
Software: Set NUM_REGS to your new count. Your channel numbers keep increasing linearly (e.g., with 3 chips, channels 0–23).
Troubleshooting
Some LEDs randomly on at power-up
Initialize with clearAll() in setup(); optionally wire MR and/or OE to Arduino pins as explained.
Nothing lights
Check VCC/GND, verify latch wiring (ST_CP). Make sure you call flush() or use regWrite() which calls it for you.
Only first 8 work
Q7′(pin 9) of chip 1 must go to DS(pin 14) of chip 2. Also confirm you’re shifting MSBFIRST and sending the last register first in the loop.
Flicker or unreliable updates with many chips
Lower clock rate (use shiftOut as is, or add small delays), keep wires short, add decoupling capacitors, ensure solid ground. Consider buffering if chain gets long.
Uneven brightness
Use individual current-limiting resistors per LED and dim via OE PWM, not a shared series potentiometer.
Frequently Asked (Useful) Variations
Can I multiplex instead to reduce current and chips?
Yes. For matrixes (e.g., 8×8), pair 74HC595 with a row/column driver (like ULN2803, TPIC6B595, or a 74HC138) and scan rows. Code is different but very scalable.
What about SPI for speed?
You can wire DS→MOSI, SH_CP→SCK, and manually toggle ST_CP as latch. Then use SPI.transfer() for much faster updates than shiftOut().
Can I use 3.3 V boards?
74HC595 typically works at 3.3–5 V. Check your particular HC family and ensure LED current and logic thresholds are respected.
Summary
Two 74HC595s = 16 LED channels using just 3 Arduino pins
Global brightness via OE on a PWM pin is cleaner than a series potentiometer
Add more chips: wire Q7′→DS, change NUM_REGS, done
The provided code presents a universal channel interface and example effects you can extend
If you want, I can also provide a version wrapped as a small C++ class (with non-blocking timers for smooth patterns) or an SPI-accelerated variant for longer chains.
Top comments (0)