Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

74HC595 shift register with ESP32 DevKit V1 — 3.3 V, hardware SPI, PWM dimming

Run a 74HC595 at 3.3 V from an ESP32 DevKit V1: data and clock on VSPI, latch on D4, PWM brightness on OE with a pull-up that keeps LEDs dark during boot.

Arduino C++Verified — core esp32 3.3.12, 3 Nov 2026Compile-only

Community draft — report a mistake

A 74HC595 turns three GPIOs into eight outputs, and chained chips give you as many as you like. It is how people drive LED bar graphs, 7-segment displays and big LED matrices from one board.

On the ESP32 DevKit V1 the chip runs from 3V3, so its inputs match the ESP32’s 3.3 V logic. Data and clock come from the VSPI hardware (D23 and D18), the latch is on D4, and the active-LOW OE pin is driven with PWM from D32 so all eight LEDs fade together. A 10 kΩ pull-up on OE keeps them dark while the ESP32 boots.

Wiring

ESP32 DevKit V1Only the pins used are shown · 3.3 V logic74HC595 8-bit shift register (DIP-16)10k → 3V3D32GNDD23D18D43V3VCCGNDDSSH_CPST_CPOEMRQ0 → LED 1 via 220 Ω to GNDQ1 → LED 2 via 220 ΩQ2 → LED 3 via 220 ΩQ3 → LED 4 via 220 ΩQ4 → LED 5 via 220 ΩQ5 → LED 6 via 220 ΩQ6 → LED 7 via 220 ΩQ7 → LED 8 via 220 ΩQ7S (not connected)
Also needed: 8 LEDs and 8 × 220 Ω resistors, 10 kΩ resistor (OE pull-up), 100 nF ceramic capacitor.
Every connection
ESP32 DevKit V174HC595 8-bit shift register (DIP-16)WireNotes
—Q0—To LED 1 via 220 Ω to GND (not drawn)
—Q1—To LED 2 via 220 Ω (not drawn)
—Q2—To LED 3 via 220 Ω (not drawn)
—Q3—To LED 4 via 220 Ω (not drawn)
—Q4—To LED 5 via 220 Ω (not drawn)
—Q5—To LED 6 via 220 Ω (not drawn)
—Q6—To LED 7 via 220 Ω (not drawn)
—Q7—To LED 8 via 220 Ω (not drawn)
3V3VCCredPin 16. Powering the chip from 3.3 V makes its inputs match the ESP32’s logic. 100 nF capacitor from VCC to GND at the chip.
GNDGNDblackPin 8.
D23DSgreenPin 14, serial data (VSPI MOSI).
D18SH_CPbluePin 11, shift clock (VSPI SCK).
D4ST_CPyellowPin 12, latch.
D32OEpurplePin 13, active-LOW output enable, driven with PWM for brightness.
3V3OEredVia 10 kΩ — Pull-up: holds the outputs off while the ESP32 boots and D32 is still floating.
3V3MRredPin 10, active-LOW reset — keep HIGH.

2–6 V part, 3.3 V board. Power it from the same voltage as your board: 3.3 V on ESP32 and Pico, 5 V on Uno. At 5 V the 74HC595 needs about 3.15 V for a HIGH, so a 3.3 V board driving a 5 V-powered chip is marginal — use a 74HCT595 at 5 V for that.

Board quirks

  • Power the 74HC595 from 3V3, not VIN. At 5 V the chip needs about 3.5 V for a HIGH, so 3.3 V signals are marginal. At 3.3 V everything matches; if you need 5 V outputs (for example to drive a 5 V relay board), use a 74HCT595 on 5 V instead.
  • At 3.3 V each output drives less current, so this guide uses 220 Ω resistors (about 5–6 mA per red LED). Keep the total under the chip’s 70 mA limit when all eight are on.
  • Data and clock use the VSPI hardware at 8 MHz — hundreds of times faster than shiftOut(), which matters when you chain many chips for a big LED display. SPI.begin(18, -1, 23, -1) leaves MISO (D19) free because the 595 never sends data back.
  • ESP32 GPIOs float for a moment at power-on, so the 10 kΩ pull-up on OE keeps the LEDs dark until the sketch has loaded known data. Without it you may see a random flash at every reset.
  • analogWrite() works on the ESP32 in core 3.x (it uses the LEDC peripheral). OE is active-LOW, so the sketch writes 255 − brightness.
  • Chain more chips by wiring Q7S (pin 9) to the next chip’s DS and sharing SH_CP, ST_CP and OE. Then send one byte per chip, last chip first.

Code

74hc595-esp32.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// 74HC595 shift register on an ESP32 DevKit V1 — hardware SPI plus PWM brightness on OE.
// VCC → 3V3, GND → GND, DS → D23 (VSPI MOSI), SH_CP → D18 (VSPI SCK), ST_CP (latch) → D4,
// OE → D32 (PWM) with a 10 kΩ pull-up to 3V3, MR → 3V3. Q0–Q7 → LED + 220 Ω each → GND.
#include <SPI.h>

constexpr uint8_t SCK_PIN = 18, MOSI_PIN = 23, LATCH_PIN = 4, OE_PIN = 32;

void writeByte(uint8_t value) {
  SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));  // 8 MHz: far faster than shiftOut()
  SPI.transfer(value);                                              // Q7 gets the first bit sent
  SPI.endTransaction();
  digitalWrite(LATCH_PIN, HIGH);  // rising edge copies the 8 bits to Q0–Q7 together
  digitalWrite(LATCH_PIN, LOW);
}

// OE is active LOW, so a brighter LED needs a lower duty on OE.
void brightness(uint8_t level) { analogWrite(OE_PIN, 255 - level); }

void setup() {
  pinMode(OE_PIN, OUTPUT);
  digitalWrite(OE_PIN, HIGH);  // outputs off until the register holds known data
  pinMode(LATCH_PIN, OUTPUT);
  digitalWrite(LATCH_PIN, LOW);
  SPI.begin(SCK_PIN, -1, MOSI_PIN, -1);  // no MISO: the 74HC595 never talks back, D19 stays free
  writeByte(0);
  brightness(255);
  Serial.begin(115200);
  Serial.println("74HC595 on VSPI: running light, then a breathing bar");
}

void loop() {
  for (uint8_t i = 0; i < 8; i++) {
    writeByte(1 << i);
    delay(70);
  }
  for (int8_t i = 6; i > 0; i--) {
    writeByte(1 << i);
    delay(70);
  }
  writeByte(0xFF);
  Serial.println("All on, fading with PWM on OE");
  for (int l = 255; l >= 0; l -= 5) {
    brightness(l);
    delay(15);
  }
  for (int l = 0; l <= 255; l += 5) {
    brightness(l);
    delay(15);
  }
  Serial.println("Pattern 0b10101010 = 170");
  writeByte(0b10101010);
  delay(600);
}

Expected serial output

Serial Monitor · 115200Output
74HC595 on VSPI: running light, then a breathing bar
All on, fading with PWM on OE
Pattern 0b10101010 = 170

Common errors

LEDs flash randomly at every reset

The OE pull-up is missing. Add 10 kΩ from OE to 3V3.

Nothing lights

MR is LOW or floating (tie it to 3V3), or the latch on D4 isn’t connected. Without a rising edge on ST_CP the outputs never change.

LEDs are very dim

Check the resistor values, and that the chip is a 74HC595 and not a 74HCT595 on 3.3 V (HCT parts are specified for 5 V).

↑↓ to move · Enter to open