How to Interface the 74HC595 Serial Shift Register with a PIC16F877A (Drive 8+ LEDs with 3 Pins)
Want to drive a bunch of LEDs (or any digital outputs) but you’re running out of GPIOs on the PIC16F877A? The 74HC595 serial-in/parallel-out (SIPO) shift register is the classic fix: you clock data in using just DATA, CLOCK, and LATCH lines, and it presents eight stable outputs on Q0–Q7. You can also daisy-chain more ‘595s to get 16, 24, 32… outputs with the same three pins.
Below is a complete, hands-on guide with wiring, timing, pitfalls, and two code options (bit-banged I/O and hardware SPI) for both MikroC PRO for PIC and MPLAB XC8.
What You’ll Learn
-
What the 74HC595 does and when to use it
-
Exact connections between PIC16F877A and 74HC595
-
Timing (CLOCK vs LATCH) and bit order
-
Clean, reusable send-byte routines (bit-bang & SPI)
-
Daisy-chaining two or more 74HC595s
-
Troubleshooting tips and common mistakes
Why use a 74HC595?
Microcontrollers have limited GPIO. The 74HC595 lets you:
-
Save pins: 3 control pins → 8 outputs (and more if chained)
-
Scale easily: add another ‘595 for +8 outputs without using more MCU pins
-
Keep outputs stable: the outputs don’t change until you hit LATCH, so you avoid flicker/glitches
Typical uses: LED bars/matrices, 7-segment displays (single or multiplexed), relays, simple digital control lines.
IC Overview (74HC595)
-
Type: SIPO (Serial-In / Parallel-Out), 8-bit
-
Voltage: 2–6 V (works great at 5 V with the PIC16F877A)
-
Two internal registers:
-
Shift register receives serial data on DS with SH_CP (shift clock)
-
Storage (latch) register updates outputs Q0–Q7 on rising edge of ST_CP (latch clock)
-
⚠️ Naming you’ll see in datasheets:
- DS = Serial Data
- SH_CP = Shift Clock (sometimes “SRCLK”)
- ST_CP = Storage/Latch Clock (sometimes “RCLK”)
- OE̅ (active-LOW Output Enable)
- MR̅ (active-LOW Master Reset)
- Q7′ (serial out for daisy-chain)
Pin Summary (16 pins)
| Pin | Name | Function / Notes |
|---|---|---|
| 14 | DS | Serial data in |
| 11 | SH_CP | Shift clock (data sampled on rising edge) |
| 12 | ST_CP | Latch clock (outputs updated on rising edge) |
| 13 | OE̅ | Output enable (active LOW). Tie to GND to always enable. |
| 10 | MR̅ | Master reset (active LOW). Tie to VCC for normal operation. |
| 9 | Q7′ | Serial out to next ‘595’s DS (for chaining) |
| 1–7,15 | Q0–Q7 | Parallel outputs |
| 8 | GND | Ground |
| 16 | VCC | +5 V |
✅ Common correction: A frequently cited PISO partner IC is 74HC165, not 74HC156.
Hardware You Need
-
PIC16F877A + 5 V supply
-
74HC595 (1 or more)
-
8× LEDs + 8× current-limit resistors (e.g., 330 Ω when using 5 V)
-
8 MHz or 20 MHz crystal + two 22 pF capacitors (PIC16F877A has no internal oscillator)
-
Breadboard & wires
Wiring (Single 74HC595N + 8 LEDs)
PIC16F877A → 74HC595 (recommended pins):
-
RC1→ DS (pin 14) – Data -
RC0→ SH_CP (pin 11) – Shift clock -
RC2→ ST_CP (pin 12) – Latch clock -
OE̅ (pin 13) → GND (always enabled)
-
MR̅ (pin 10) → VCC (no resets)
-
VCC (pin 16) → +5 V
-
GND (pin 8) → GND
Outputs & LEDs:
-
Q0–Q7 (pins 15,1–7) → LED → resistor → GND (or VCC, depending on your polarity; just be consistent)
💡 If you ever want to blank all outputs in one shot, route OE̅ to a PIC pin instead of GND and set it HIGH to disable outputs.
Timing in One Picture (conceptually)
-
Put the next data bit on DS
-
Pulse SH_CP (rising edge) → bit shifts in
-
Repeat for 8 bits (MSB-first or LSB-first; just be consistent)
-
Pulse ST_CP (rising edge) → all Q0–Q7 update at once
Bit Order (important!)
You can shift MSB-first or LSB-first. Choose one and use it everywhere (your patterns must match). In the code below, we’ll do LSB-first because it’s simple for LED sequences; I’ll show you how to flip it.
| Part Number | Description | Orderable / Packaging | Function | Temp Range | Mounting | Package & Width | Package Code | Notes / Status |
|---|---|---|---|---|---|---|---|---|
| SN74HC595DBR | IC SR TRI-STATE 8BIT 16-SSOP | Tape & Reel (TR) | Serial to Parallel, Serial | -40°C ~ 85°C | Surface Mount | 16-SSOP (0.209″, 5.30mm) | 16-SSOP | — |
| SN74HC595ADBR | IC SR TRI-STATE 8BIT 16-SSOP | Tape & Reel (TR) | Serial to Parallel, Serial | -40°C ~ 85°C | Surface Mount | 16-SSOP (0.209″, 5.30mm) | 16-SSOP | — |
| CD74HC595SM96 | IC SR TRI-STATE 8BIT 16-SSOP | Tape & Reel (TR) | Serial to Parallel, Serial | -55°C ~ 125°C | Surface Mount | 16-SSOP (0.209″, 5.30mm) | 16-SSOP | Extended temp |
MikroC PRO for PIC (Bit-Banged I/O)
Set your project to HS oscillator and match the crystal you use (8 MHz example below).
// MikroC PRO for PIC
// PIC16F877A @ 8 MHz (HS)
// Simple bit-bang driver for 74HC595 (LSB-first)
sbit DATA_pin at PORTC.B1; // DS
sbit CLOCK_pin at PORTC.B0; // SH_CP
sbit LATCH_pin at PORTC.B2; // ST_CP
void pulse_clock() { CLOCK_pin = 1; Delay_us(2); CLOCK_pin = 0; Delay_us(2);
}
void latch_update() { LATCH_pin = 1; Delay_us(2); LATCH_pin = 0;
}
// Send one byte, LSB-first
void shiftOutLSB(unsigned char val) { unsigned char i; for (i = 0; i < 8; i++) { DATA_pin = (val >> i) & 0x01; pulse_clock(); } latch_update();
}
void main() { TRISC.B0 = 0; // CLOCK TRISC.B1 = 0; // DATA TRISC.B2 = 0; // LATCH CLOCK_pin = 0; DATA_pin = 0; LATCH_pin = 0;
while(1) { // Walk a single '1' across Q0..Q7 for (unsigned char b = 0; b < 8; b++) { shiftOutLSB(1 << b); Delay_ms(150); } // All off shiftOutLSB(0x00); Delay_ms(200); // All on shiftOutLSB(0xFF); Delay_ms(200); }
}
MSB-first version (swap the loop body):
void shiftOutMSB(unsigned char val) { char i; for (i = 7; i >= 0; i--) { DATA_pin = (val >> i) & 0x01; pulse_clock(); } latch_update();
}
MPLAB XC8 (Bit-Banged I/O)
Set configuration bits for HS crystal and match _XTAL_FREQ to your crystal (8 MHz shown). If you use 20 MHz, set _XTAL_FREQ 20000000 and delays will scale.
// MPLAB XC8, PIC16F877A @ 8 MHz (HS)
#include <xc.h>
#define _XTAL_FREQ 8000000
// CONFIG (adjust to your project as needed)
#pragma config FOSC = HS, WDTE = OFF, PWRTE = OFF, BOREN = ON, LVP = OFF, CPD = OFF, WRT = OFF, CP = OFF
#define DATA_pin RC1 // DS
#define CLOCK_pin RC0 // SH_CP
#define LATCH_pin RC2 // ST_CP
void pulse_clock(void) { CLOCK_pin = 1; __delay_us(2); CLOCK_pin = 0; __delay_us(2);
}
void latch_update(void) { LATCH_pin = 1; __delay_us(2); LATCH_pin = 0;
}
// LSB-first
void shiftOutLSB(unsigned char val) { for (unsigned char i = 0; i < 8; i++) { DATA_pin = (val >> i) & 0x01; pulse_clock(); } latch_update();
}
void main(void) { TRISC0 = 0; // CLOCK TRISC1 = 0; // DATA TRISC2 = 0; // LATCH RC0 = 0; RC1 = 0; RC2 = 0;
while(1) { for (unsigned char b = 0; b < 8; b++) { shiftOutLSB(1 << b); __delay_ms(150); } shiftOutLSB(0x00); __delay_ms(200); shiftOutLSB(0xFF); __delay_ms(200); }
}
Using the PIC’s Hardware SPI (MSSP) — Faster & Cleaner
The PIC16F877A has an MSSP module that can operate as SPI Master. This lets you blast out a byte with one register write—much faster and lower CPU overhead than bit-banging.
Connections (SPI Master):
-
RC3/SCK→ SH_CP -
RC5/SDO→ DS -
A spare GPIO (e.g.,
RC2) → ST_CP (latch) -
OE̅ → GND, MR̅ → VCC
MPLAB XC8 (SPI example, MSB-first by hardware):
#include <xc.h>
#define _XTAL_FREQ 8000000
#pragma config FOSC = HS, WDTE = OFF, PWRTE = OFF, BOREN = ON, LVP = OFF, CPD = OFF, WRT = OFF, CP = OFF
#define LATCH_TRIS TRISC2
#define LATCH_LAT RC2
void spi_init(void) { // SDO=RC5 output, SCK=RC3 output TRISC3 = 0; // SCK TRISC5 = 0; // SDO LATCH_TRIS = 0; LATCH_LAT = 0;
// SPI Master, Fosc/16, CKP=0, CKE=1 (Mode 0,0) SSPSTAT = 0b01000000; // CKE=1 SSPCON = 0b00100001; // SSPEN=1, CKP=0, Fosc/16
}
void latch_update(void) { LATCH_LAT = 1; __delay_us(2); LATCH_LAT = 0;
}
void shiftOutSPI(unsigned char val) { SSPBUF = val; // start transfer while(!SSPSTATbits.BF); // wait done latch_update(); // update outputs
}
void main(void) { spi_init();
while(1) { for (unsigned char b = 0; b < 8; b++) { // If you want LSB-first behavior visually on Q0..Q7, // you can reverse bits before sending (optional). unsigned char v = (1 << b); // send directly (MSB-first over the wire; 74HC595 doesn't care as long as you're consistent) shiftOutSPI(v); __delay_ms(120); } shiftOutSPI(0x00); __delay_ms(200); shiftOutSPI(0xFF); __delay_ms(200); }
}
📝 Notes
- SPI mode CKP=0, CKE=1 (Mode 0,0) is safe for the 74HC595; data is sampled on SCK rising edge.
- If your display pattern looks reversed, swap to a bit-reversed lookup before sending or choose LSB/MSB-first consistently across your project.
Daisy-Chaining Two or More 74HC595s
To get 16, 24, 32… outputs:
-
First ‘595 Q7′ (pin 9) → next ‘595 DS (pin 14)
-
Share CLOCK (SH_CP) and LATCH (ST_CP) to all chips
-
Send N bytes back-to-back (last byte you send ends up on the first ‘595 in the chain), then one LATCH pulse to update all.
Example (bit-bang, 2 chips):
void shiftOut2Bytes(unsigned char b1, unsigned char b2) { // Send the byte destined for the furthest chip first shiftOutLSB(b2); // goes to second chip shiftOutLSB(b1); // then first chip // shiftOutLSB already calls latch_update().
}
Common Mistakes & Troubleshooting
-
SH_CP vs ST_CP swapped:
-
SH_CP is the shift clock; ST_CP is the latch clock. If LEDs flicker or show partial updates, double-check this.
-
-
No current-limiting resistors: LEDs may burn out or draw too much current from Q pins. Use 220–470 Ω per LED.
-
OE̅ left floating: Tie to GND (or drive from MCU). Floating can randomly disable outputs.
-
MR̅ not tied to VCC: If left floating/LOW, the register keeps resetting → no output.
-
Wrong delays / oscillator setting:
_XTAL_FREQmust match your crystal in XC8; otherwise delays are wrong. -
Bit order mismatch: If your LED pattern looks backward, you’re sending MSB-first while your mental model is LSB-first (or vice versa). Standardize and stick to it.
-
Supply & decoupling: Add a 0.1 µF ceramic close to the ‘595 VCC pin. Long wires benefit from a bulk cap (e.g., 10 µF).
Extending to 7-Segment and LED Matrices
-
Single 7-segment (static): one ‘595 is enough; map segments to Q0–Q7.
-
4-digit multiplexed: use one ‘595 for segments and a transistor array (or another ‘595 with PNP/NPN drivers) for digit selects.
-
8×8 matrix: two ‘595s—one for rows, one for columns—plus multiplexing logic in code.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.