Arduino boards come with a decent number of digital I/O pins, but sometimes that’s just not enough. For example, controlling a 7-segment display takes 8 I/O pins for just one digit. Similarly, an 8×8 LED matrix needs 16 pins, which quickly exhausts the available GPIOs on most Arduino boards.
That’s where the 74HC595 shift register comes in handy. With just three GPIO pins and this simple IC, you can increase the number of output pins on your Arduino boards. A single 74HC595 IC can control 8 digital outputs, and you can even increase the number of I/O by cascading multiple shift registers.
In this tutorial, you’ll learn how to use the 74HC595 shift register with Arduino and cascade multiple shift registers to drive a large number of LEDs.
Table of Contents
What is a Shift Register?
A shift register is a digital circuit designed to store and shift binary data in a specific direction, typically one bit at a time. The name comes from its core function—shifting data through a series of flip-flops.
A typical n-bit shift register is made up of n
flip-flops (usually D-type), connected in a cascade configuration. Each flip-flop stores a single bit, and data moves from one flip-flop to the next on the rising or falling edge of a shared clock signal. This synchronized data flow makes shift registers ideal for a wide range of embedded applications.
Common Uses of Shift Registers
- Temporary Data Storage in Digital Systems
- Data Transfer
- Serial-to-Parallel Data Conversion
- Parallel-to-Serial Data Conversion
Types of Shift Registers:
Shift registers are generally classified into four main types based on their input/output configuration:
- Serial In – Serial Out (SISO)
- Serial In – Parallel Out (SIPO)
- Parallel In – Serial Out (PISO)
- Parallel In – Parallel Out (PIPO)
74HC595 Shift Register
The 74HC595 is a Serial-In Parallel-Out (SIPO) shift register. It allows you to control 8 output pins using just 3 pins from an Arduino. The 74HC595 IC contains two 8-bit registers inside:
- The Shift Register – Accepts data serially, one bit at a time.
- The Storage Register (Latch) – Holds the data and sends it to the output pins in parallel.
When you send data to the SER (Serial Data Input) pin and give a clock pulse to the SRCLK (Shift Register Clock) pin, each rising edge of the clock moves the existing bits one step forward inside the shift register, and a new bit enters from the SER pin.
A latch is placed between the shift register and the output pins to temporarily hold the data bits, so that the output doesn’t change with every incoming bit.
Once all 8 bits are loaded into the shift register, a pulse is required at the RCLK (Register Clock or Latch Pin) to update the latches, and the 8-bit data becomes available at the output pins (QA to QH) all at once.
The pin diagram for the 74HC595 Shift Register and all the functions of the pins are given below.
74HC595 Pinout
The 74HC595 shift register is available in a 16-pin DIP or SOIC package. In this tutorial, we’ll use the DIP package. The pinout for the DIP 74HC595 shift register is shown below.

A brief description of all the pins is given below.
Name | Pin | Description |
---|---|---|
VCC | 16 | Power supply pin. Connect to +5V. |
GND | 8 | Ground pin. Connect to GND. |
SRCLR | 10 | Shift register clear (active LOW). Keep HIGH to avoid clearing. |
SRCLK | 11 | Shift register clock. Shifts data on the rising edge. |
RCLK | 12 | Latch (register) clock. Moves data to the output on the rising edge. |
OE | 13 | Output enable (active LOW). Tie to GND to enable outputs. |
SER | 14 | Serial data input. Reads 1 bit per clock cycle. |
QA–QH | 15, 1–7 | 8-bit parallel data outputs (QA = Pin 15, QB = Pin 1, …, QH = Pin 7). |
QH’ | 9 | Serial out. Connect to the next register’s SER for chaining. |
You can see that there are two power supply pins – VCC and GND. These pins are used to provide a 5V power supply to the IC.
Then, there are four control pins – SRCLK, RCLK, SRCLR, and OE.
SRCLK is the shift register clock pin. Data shifts into the register on the rising edge of this clock pulse. RCLK is the latch (register) clock pin. Data moves from the shift register to the output latch on the rising edge of this clock.
SRCLR is the shift register clear pin, used to reset the shift register. This is an active-low pin. In most cases, we don’t need to clear the shift register manually. So you can keep it always high. OE is the output enable pin, which controls whether the latched data appears on the output pins. This is also an active-low pin – connecting it to ground enables the outputs (QA to QH).
The remaining 10 pins are data pins – SER, QA-QH (8-bit parallel output) and QH’. SER is the serial data input pin, which takes the serial data from the microcontroller. QA-QH are the 8-bit parallel output pins. QH’ is the serial data out pin, which is used to cascade multiple shift registers together.
Wiring the 74HC595 with Arduino
Connecting the shift register to the Arduino is very simple. First, place the shift register on a breadboard, and connect the VCC, GND, input, and control pins to the Arduino. Then, connect the output devices to the shift register.
So, let’s start by placing the shift register on the breadboard.
Place the shift register on the breadboard as shown in the image below. Make sure that each side of the IC is seated across the center gap, so the pins are on opposite rows of the breadboard.
First, connect the VCC to the Arduino 5V output and the GND to the Arduino ground pin.
Then connect the input data pin and the two clock pins to the Arduino. Connect the SER to pin 8, RCLK to pin 9, and SRCLK to pin 10.
There are two other control pins that we won’t use in this example — SRCLR and OE — but they must not be left floating. Connect SRCLR (pin 10) to the Arduino 5V pin and OE to the GND.
Leave the QH’ pin open for now; we will use this pin later in this tutorial.
The remaining eight pins (QA to QH – pins 15, 1–7) are the 8-bit output pins. In this example, we’ll use the shift register to drive eight LEDs, so connect eight LEDs to these output pins.
Connect the positive leg (long leg) of each LED to one of the output pins. Connect the negative leg (short leg) of all LEDs to a common ground line on the breadboard, which must be connected to the Arduino’s GND pin as well.
To protect the LEDs, add a 200–300Ω resistor in series with each one.
A summary of the PIN connection is given below.
Shift Register Pins | Connected to | |
---|---|---|
VCC (16) | ➟ | Arduino 5V |
GND (8) | ➟ | Arduino Ground |
SER (14) | ➟ | Arduino Digital Pin 8 |
RCLK (12) | ➟ | Arduino Digital Pin 9 |
SRCLK (11) | ➟ | Arduino Digital Pin 10 |
8 Data Pins | ➟ | 8 LEDs (+ve end) |
OE (Pin 13) | ➟ | Ground |
SRCLR (10) | ➟ | 5V |
QH‘ | ➟ | No Connection |

Arduino Code for 74HC595
Generating an input signal for the shift register is a bit complex because it requires three Arduino pins to work in sync.
One pin (SER) sends the input data bits serially. Another pin is used to generate the clock pulses (SRCLK) for shifting data into the register. A third pin provides the latch clock (RCLK) to transfer the data from the shift register to the output latches. All three signals—data, shift clock, and latch clock—must be carefully synchronized to ensure correct data transfer and output.
To simplify this process, Arduino provides a built-in function called shiftOut()
. This function handles the timing and bit shifting internally, making it much easier to send serial data to devices like the 74HC595.
First, we’ll look at how the shiftOut()
function works, and then we’ll write some Arduino code to send data to the 74HC595.
The syntax for the shiftOut()
function is:
shiftOut(dataPin, clockPin, bitOrder, data)
You can see that this function requires four arguments. The first two arguments are the data and clock pins.
Then comes the bit order, which defines the way bits are shifted out. The bit order can be MSBFIRST
or LSBFIRST
(Most Significant Bit First or Least Significant Bit First).
The last argument is the data to be shifted out, which should be of type byte
.
Arduino Code – Send 8-bit Data to the Shift Register
The code below will send a single byte (10101010) to the shift register. You can see the output in the LED array.
int dataPin = 8; // SER, serial data input
int latchPin = 9; // RCLK, storage register clock input pin
int clockPin = 10; // SRCLK, shift register clock input
byte leds = 0b10101010;
void setup() {
// Set the pins as outputs
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(latchPin, OUTPUT);
}
void loop() {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, leds);
digitalWrite(latchPin, HIGH);
}
You can see that we create three variables – latch pin, clock pin, and data pin to hold the Arduino PIN that is connected to the corresponding shift register pins. We also create a variable of type byte to hold the byte data to be sent to the shift register.
Then, in the setup section, we make all three pins output pins.
In the loop section, we pull the latch pin LOW, send the data using the shiftOut()
function, and then set the latch pin HIGH again to write the data to the latch. Since this is a one-time task, you can move it to the setup section of the code.
Arduino Code – Send Multiple Bytes to the Shift Register
The above example displays only a single LED pattern. To create an LED effect, we need to send multiple bytes, one byte per frame.
The code below will send a byte array to the shift register, which creates an LED pattern on the output pins.
int dataPin = 8; // SER, serial data input
int latchPin = 9; // RCLK, storage register clock input pin
int clockPin = 10; // SRCLK, shift register clock input
byte ledPattern[9] = {
0b00000000,
0b10000000,
0b11000000,
0b11100000,
0b11110000,
0b11111000,
0b11111100,
0b11111110,
0b11111111
};
void setup() {
// Set the pins as outputs
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(latchPin, OUTPUT);
}
void loop() {
for (int i = 0; i < 9; i++) {
displayPattern(i);
delay(100);
}
}
void displayPattern(int pattern) {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, ledPattern[pattern]);
digitalWrite(latchPin, HIGH);
}
The code is very similar to the previous one.
There are two main things to look at here: we create a data array (ledPattern), an 8-bit data set to generate different patterns on LEDs.
We also create a custom function (displayPattern) to send 8 bits of data to the shift register. It will avoid complexity in the loop section.
In the loop section, we use our custom function, displayPattern, to send the LED sequence data to the shift registers, 8 bits at a time. We use a for loop that helps to send 9 datasets one by one.
Arduino Code – Multiple LED Effects with a Shift Register & 8 LEDs
int dataPin = 8; // SER, serial data input
int latchPin = 9; // RCLK, storage register clock input pin
int clockPin = 10; // SRCLK, shift register clock input
int patternDelay = 1000;
const int repeatCounter1 = 6; // Counter for single loop effects
const int repeatCounter2 = 4; // Counter for double loop effects
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
// Write a byte to 74HC595
void writeToShiftRegister(byte data) {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, data);
digitalWrite(latchPin, HIGH);
}
void loop() {
singleChase(); // Single LED moving left to right
bounce(); // Single led bouncing from one side to another
fillAndClear(); // Fill from one side and clear from opposite
reverseFillAndClear(); // Fill from one side and clear from same side
fillAndClearAlternate(); // Fill and Bounce back
alternateBlink(); // Blink LEDs alternatively
expandFromCenter(); // Fill all the LEDs from center
contractToCenter(); // Fill all the LEDs from side
expandAndContract(); // Fill from center, then clear from side
meetInMiddle(); // Single LED move from both side to center
splitFromMiddle(); // Single LED move from center to side
splitAndMeet(); // Single LED repeat both
}
// Single LED Moving Left to Right
void singleChase() {
int delayTime = 50;
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 8; i++) {
writeToShiftRegister(1 << i);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Single LED Bouncing From One Side to Another
void bounce() {
int delayTime = 50;
for (int r = 0; r < repeatCounter2; r++) {
for (int i = 0; i < 8; i++) {
writeToShiftRegister(1 << i);
delay(delayTime);
}
for (int i = 6; i > 0; i--) {
writeToShiftRegister(1 << i);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill from one side and clear from opposite
void fillAndClear() {
int delayTime = 50;
uint8_t data = 0;
for (int r = 0; r < repeatCounter2; r++) {
for (int i = 0; i < 8; i++) {
data |= (1 << i);
writeToShiftRegister(data);
delay(delayTime);
}
for (int i = 7; i >= 0; i--) {
data &= ~(1 << i);
writeToShiftRegister(data);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill from one side and clear from same side
void reverseFillAndClear() {
int delayTime = 50;
uint8_t data = 0;
for (int r = 0; r < repeatCounter2; r++) {
// Fill from left to right (bit 0 to 8)
for (int i = 0; i < 8; i++) {
data |= (uint8_t)1 << i;
writeToShiftRegister(data);
delay(delayTime);
}
// Clear from left to right (bit 0 to 8)
for (int i = 0; i < 8; i++) {
data &= ~((uint8_t)1 << i);
writeToShiftRegister(data);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill and Bounce back
void fillAndClearAlternate() {
int delayTime = 50;
uint8_t data;
for (int r = 0; r < repeatCounter2; r++) {
// Fill from left to right, clear from left to right
data = 0;
for (int i = 0; i < 8; i++) {
data |= (uint8_t)1 << i;
writeToShiftRegister(data);
delay(delayTime);
}
for (int i = 0; i < 8; i++) {
data &= ~((uint8_t)1 << i);
writeToShiftRegister(data);
delay(delayTime);
}
// Fill from right to left, clear from right to left
data = 0;
for (int i = 7; i >= 0; i--) {
data |= (uint8_t)1 << i;
writeToShiftRegister(data);
delay(delayTime);
}
for (int i = 7; i >= 0; i--) {
data &= ~((uint8_t)1 << i);
writeToShiftRegister(data);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Blink LEDs alternatively
void alternateBlink() {
int delayTime = 200;
for (int r = 0; r < 6; r++) {
writeToShiftRegister(0b10101010);
delay(delayTime);
writeToShiftRegister(0b01010101);
delay(delayTime);
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill all the LEDs from center
void expandFromCenter() {
const int delayTime = 150;
const byte pattern[] = {
0b00000000,
0b00011000,
0b00111100,
0b01111110,
0b11111111
};
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 5; i++) {
writeToShiftRegister(pattern[i]);
delay(150);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill all the LEDs from side
void contractToCenter() {
const int delayTime = 150;
const uint16_t pattern[] = {
0b11111111,
0b01111110,
0b00111100,
0b00011000,
0b00000000
};
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 5; i++) {
writeToShiftRegister(pattern[i]);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill from center, then clear from side
void expandAndContract() {
const int delayTime = 50;
// Expansion + full ON frame
const uint8_t pattern[] = {
0b00000000,
0b00011000,
0b00111100,
0b01111110,
0b11111111
};
for (int r = 0; r < repeatCounter2; r++) {
for (int i = 0; i < 5; i++) {
writeToShiftRegister(pattern[i]);
delay(delayTime);
}
for (int i = 3; i >= 0; i--) {
writeToShiftRegister(pattern[i]);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Single LED move from both side to center
void meetInMiddle() {
int delayTime = 120;
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 4; i++) {
byte left = (1 << i);
byte right = (1 << (7 - i));
writeToShiftRegister(left | right);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Single LED move from center to side
void splitFromMiddle() {
int delayTime = 120;
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 4; i++) {
byte left = (1 << (3 - i));
byte right = (1 << (4 + i));
writeToShiftRegister(left | right);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Single LED repeat both
void splitAndMeet() {
int delayTime = 50;
for (int r = 0; r < repeatCounter2; r++) {
// From edges to middle
for (int i = 0; i < 4; i++) {
uint8_t pattern = (1 << i) | (1 << (7 - i));
writeToShiftRegister(pattern);
delay(delayTime);
}
// From middle to edges
for (int i = 3; i >= 0; i--) {
uint8_t pattern = (1 << i) | (1 << (7 - i));
writeToShiftRegister(pattern);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
Cascading Multiple Shift Registers

One of the most useful things is that you can connect multiple shift registers serially, and still control them using the same number of Arduino pins. That means you can control 8,16, 24, and more I/O pins using only three Arduino pins.
Let’s see how to control 16 LEDs using 2 Shift registers.
Circuit Diagram
For this circuit, use two breadboards side by side to keep the wiring neat and clean.
Place two shift registers on one breadboard, and keep their data pins on one side. Use the second breadboard to place the 16 LEDs. Connect the ground legs of all LEDs to the ground line, and the positive legs to the 16 output pins of the two shift registers through individual 220 Ω resistors.
Connect the breadboard power lines together (+ve to +ve, -ve to -ve).
Next, connect the VCC pins of both shift registers to the 5V line and the GND pins to the ground line. Connect the OE (Output Enable) pins of both ICs to ground, and connect SRCLR (Shift Register Clear) to the 5V line.
Use a common line from Arduino digital pin 9 to drive both RCLK pins, and another common line from digital pin 10 for both SRCLK pins.
Then, connect the SER pin of IC1 to Arduino digital pin 8, and connect IC1’s QH’ pin to the SER pin of the second IC.
The complete circuit diagram is shown below.

Refer to the pin connection table below for a quick and easy setup.
IC1 Pins | Connected to | IC2 Pins | Connected to | ||
---|---|---|---|---|---|
VCC (16) | ➟ | Arduino 5V | VCC (16) | ➟ | Arduino 5V |
GND (8) | ➟ | Arduino Ground | GND (8) | ➟ | Arduino Ground |
SER (14) | ➟ | Arduino Digital Pin 8 | SER (14) | ➟ | IC1 QH‘ Pin (9) |
RCLK (12) | ➟ | Arduino Digital Pin 9 | RCLK (12) | ➟ | Arduino Digital Pin 9 |
SRCLK (11) | ➟ | Arduino Digital Pin 10 | SRCLK (11) | ➟ | Arduino Digital Pin 10 |
8 Data Pins | ➟ | LED 1 to 8 | 8 Data Pins | ➟ | LED 9 to 16 |
OE (Pin 13) | ➟ | Ground | OE (Pin 13) | ➟ | Ground |
SRCLR (10) | ➟ | 5V | SRCLR (10) | ➟ | 5V |
QH‘ (9) | ➟ | IC2 SER Pin (14) | QH‘ (9) | ➟ | No Connection |
Note that IC1 refers to the first shift register, which is connected directly to the Arduino data pin, and IC2 refers to the second shift register, which is daisy-chained to the first shift register.
Your circuit is complete. Now test the setup using the code below.
Arduino Code – Cascading Two Shift Registers
The code below helps to test the circuit and the orientation of the LEDs.
int dataPin = 8; // SER
int latchPin = 9; // RCLK
int clockPin = 10; // SRCLK
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
// Send 16-bit data
void writeToShiftRegister(uint16_t data) {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, (data >> 8) & 0xFF); // High byte → IC2
shiftOut(dataPin, clockPin, MSBFIRST, data & 0xFF); // Low byte → IC1
digitalWrite(latchPin, HIGH);
}
void loop() {
for (int i = 0; i < 16; i++) {
writeToShiftRegister((uint16_t)1 << i);
delay(200);
}
}
Upload the code to your Arduino board. If everything is correct, one LED will light up and move from one side to another.
Explaining the code
The Arduino shiftOut() function operates in 8-bit mode, so for 16-bit data, we need to break it into two parts and then send them using the shiftOut() function. We will do it using a custom function – writeToShiftRegister().
// Send 16-bit data
void writeToShiftRegister(uint16_t data) {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, (data >> 8) & 0xFF); // High byte → IC2
shiftOut(dataPin, clockPin, MSBFIRST, data & 0xFF); // Low byte → IC1
digitalWrite(latchPin, HIGH);
}
To explain the working of this function, let’s take a 16-bit data as an example: 10101011 11001101. Here, the first byte (high byte) is 10101011 and will go to IC2, the Second byte (low byte) is 11001101
and will go to IC1.
This is done by calling the shiftOut()
function twice.
shiftOut(dataPin, clockPin, MSBFIRST, (data >> 8) & 0xFF);
shiftOut(dataPin, clockPin, MSBFIRST, data & 0xFF);
We will understand these bitwise operations with the help of a step-by-step operation table.
Step | Operation | Binary Result | Description |
---|---|---|---|
0 | data | 10101011 11001101 | |
1 | data >> 8 | 00000000 10101011 | Shift right by 8 to get the High Byte |
2 | (data >> 8) & 11111111 | 10101011 | Mask with 0xFF to keep 8 bits |
→ sent to shiftOut() | 10101011 | Goes to IC2 (2nd shift reg) | |
3 | data & 11111111 | 11001101 | Mask to get Low Byte directly |
→ sent to shiftOut() | 11001101 | Goes to IC1 (1st shift reg) |
Using the same logic, you can send data to 3, 4, or more shift registers.
Arduino Code – LED Effects with Two Shift Registers & 16 LEDs
Now, you have understood how to work with multiple shift registers. Now upload the code below to your Arduino board, and enjoy some cool LED effects.
int dataPin = 8; // SER
int latchPin = 9; // RCLK
int clockPin = 10; // SRCLK
int patternDelay = 1000;
const int repeatCounter1 = 4; // Counter for single loop effects
const int repeatCounter2 = 2; // Counter for double loop effects
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
// Send 16-bit data
void writeToShiftRegister(uint16_t data) {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, (data >> 8) & 0xFF); // High byte → IC2
shiftOut(dataPin, clockPin, MSBFIRST, data & 0xFF); // Low byte → IC1
digitalWrite(latchPin, HIGH);
}
void loop() {
singleChase(); // Single LED moving left to right
bounce(); // Single LED bouncing from one side to another
fillAndClear(); // Fill from one side and clear from opposite
reverseFillAndClear(); // Fill from one side and clear from same side
fillAndClearAlternate(); // Fill and Bounce back
alternateBlink(); // Blink LEDs alternatively
expandFromCenter(); // Fill all the LEDs from center
contractToCenter(); // Fill all the LEDs from side
expandAndContract(); // Fill from center, then clear from side
meetInMiddle(); // Single LED move from both side to center
splitFromMiddle(); // Single LED move from center to side
splitAndMeet(); // Single LED repeat both
randomSparkle(); // Single LED Blink Randomly
}
// Single LED moving left to right
void singleChase() {
int delayTime = 30;
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 16; i++) {
writeToShiftRegister((uint16_t)1 << i);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Single LED bouncing from one side to another
void bounce() {
int delayTime = 30;
for (int r = 0; r < repeatCounter2; r++) {
for (int i = 0; i < 16; i++) {
writeToShiftRegister((uint16_t)1 << i);
delay(delayTime);
}
for (int i = 14; i >= 0; i--) {
writeToShiftRegister((uint16_t)1 << i);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill from one side and clear from opposite
void fillAndClear() {
int delayTime = 30;
uint16_t data = 0;
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 16; i++) {
data |= (uint16_t)1 << i;
writeToShiftRegister(data);
delay(delayTime);
}
for (int i = 15; i >= 0; i--) {
data &= ~((uint16_t)1 << i);
writeToShiftRegister(data);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill from one side and clear from same side
void reverseFillAndClear() {
int delayTime = 30;
uint16_t data = 0;
for (int r = 0; r < repeatCounter1; r++) {
// Fill from left to right (bit 0 to 15)
for (int i = 0; i < 16; i++) {
data |= (uint16_t)1 << i;
writeToShiftRegister(data);
delay(delayTime);
}
// Clear from left to right (bit 0 to 15)
for (int i = 0; i < 16; i++) {
data &= ~((uint16_t)1 << i);
writeToShiftRegister(data);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill and Bounce back
void fillAndClearAlternate() {
int delayTime = 20;
uint16_t data;
for (int r = 0; r < repeatCounter2; r++) {
// Fill from left to right, clear from left to right
data = 0;
for (int i = 0; i < 16; i++) {
data |= (uint16_t)1 << i;
writeToShiftRegister(data);
delay(delayTime);
}
for (int i = 0; i < 16; i++) {
data &= ~((uint16_t)1 << i);
writeToShiftRegister(data);
delay(delayTime);
}
// Fill from right to left, clear from right to left
data = 0;
for (int i = 15; i >= 0; i--) {
data |= (uint16_t)1 << i;
writeToShiftRegister(data);
delay(delayTime);
}
for (int i = 15; i >= 0; i--) {
data &= ~((uint16_t)1 << i);
writeToShiftRegister(data);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Blink LEDs alternatively
void alternateBlink() {
int delayTime = 150;
for (int r = 0; r < 6; r++) {
writeToShiftRegister(0b1010101010101010);
delay(delayTime);
writeToShiftRegister(0b0101010101010101);
delay(delayTime);
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill all the LEDs from center
void expandFromCenter() {
const int delayTime = 60;
// Expansion + full ON frame
const uint16_t pattern[] = {
0b0000000000000000,
0b0000000110000000,
0b0000001111000000,
0b0000011111100000,
0b0000111111110000,
0b0001111111111000,
0b0011111111111100,
0b0111111111111110,
0b1111111111111111
};
for (int r = 0; r < repeatCounter1; r++) {
// Expand
for (int i = 0; i < 9; i++) {
writeToShiftRegister(pattern[i]);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill all the LEDs from side
void contractToCenter() {
const int delayTime = 60;
const uint16_t pattern[] = {
0b1111111111111111,
0b0111111111111110,
0b0011111111111100,
0b0001111111111000,
0b0000111111110000,
0b0000011111100000,
0b0000001111000000,
0b0000000110000000,
0b0000000000000000
};
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 9; i++) {
writeToShiftRegister(pattern[i]);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Fill from center, then clear from side
void expandAndContract() {
const int delayTime = 20;
// Expansion + full ON frame
const uint16_t pattern[] = {
0b0000000000000000,
0b0000000110000000,
0b0000001111000000,
0b0000011111100000,
0b0000111111110000,
0b0001111111111000,
0b0011111111111100,
0b0111111111111110,
0b1111111111111111
};
for (int r = 0; r < repeatCounter1; r++) {
// Expand
for (int i = 0; i < 9; i++) {
writeToShiftRegister(pattern[i]);
delay(delayTime);
}
// Contract (excluding the fully ON state again)
for (int i = 7; i >= 0; i--) {
writeToShiftRegister(pattern[i]);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Single LED move from both side to center
void meetInMiddle() {
int delayTime = 60;
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 8; i++) {
uint16_t left = (uint16_t)1 << i;
uint16_t right = (uint16_t)1 << (15 - i);
writeToShiftRegister(left | right);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Single LED move from center to side
void splitFromMiddle() {
int delayTime = 60;
for (int r = 0; r < repeatCounter1; r++) {
for (int i = 0; i < 8; i++) {
uint16_t left = (uint16_t)1 << (7 - i);
uint16_t right = (uint16_t)1 << (8 + i);
writeToShiftRegister(left | right);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Single LED repeat both
void splitAndMeet() {
int delayTime = 20;
for (int r = 0; r < 6; r++) {
// From edges to middle
for (int i = 0; i < 8; i++) {
uint16_t pattern = (1 << i) | (1 << (15 - i));
writeToShiftRegister(pattern);
delay(delayTime);
}
// From middle to edges
for (int i = 7; i >= 0; i--) {
uint16_t pattern = (1 << i) | (1 << (15 - i));
writeToShiftRegister(pattern);
delay(delayTime);
}
}
writeToShiftRegister(0);
delay(patternDelay);
}
// Random sparkle
void randomSparkle() {
for (int r = 0; r < 20; r++) {
uint16_t randomBit = (uint16_t)1 << random(0, 16);
writeToShiftRegister(randomBit);
delay(100);
}
writeToShiftRegister(0);
delay(patternDelay);
}
Conclusion
In this tutorial, you have learned how to use a shift register with Arduino. You have also learned how to cascade multiple shift registers together.
In the next tutorial, I will show you how to use 6 shift registers to control 16 RGB LEDs.
Stay tuned for more interesting projects and tutorials.