74HC595 移位寄存器简介
74HC595 是一个非常流行的“串入并出”(Serial-In, Parallel-Out)移位寄存器,它允许你使用微控制器的少量引脚(通常是 3 个)来控制多达 8 个(或更多,通过级联)输出设备,如 LED、继电器等。

主要优点:
- 节省 I/O 引脚:只用 3 个引脚就能控制 8 个输出。
- 简化布线:对于需要大量输出的项目,可以极大简化电路板设计。
- 可级联:可以将多个 74HC595 级联起来,轻松扩展到 16、24、32 个或更多输出。
引脚功能(关键引脚):
- DS (Serial Data):串行数据输入,你想要输出的数据一位一位地从这里送入。
- SH_CP (Shift Register Clock):移位寄存器时钟,当此引脚从低电平跳变到高电平时,DS 引脚上的数据被锁入移位寄存器,并内部移位一位。
- ST_CP (Storage Register Clock / Latch):存储寄存器时钟(也称锁存时钟),当此引脚从低电平跳变到高电平时,移位寄存器中的 8 位数据被一次性“复制”到存储寄存器,并输出到 Q0-Q7 引脚。这是实现“并行输出”的关键步骤。
- OE (Output Enable):输出使能,低电平有效,当 OE 为低电平时,Q0-Q7 正常输出;当 OE 为高电平时,所有输出为高阻态(相当于断开连接),如果不需要控制输出开关,可以直接接地。
- MR (Master Reset):主复位,低电平有效,当 MR 为低电平时,移位寄存器和存储寄存器的内容被清零,如果不需要复位功能,可以直接接 VCC。
- Q7' (Serial Out):串行输出,用于级联多个 74HC595,连接到下一个芯片的 DS 引脚。
硬件连接 (Arduino + 74HC595)
我们将使用一个简单的示例:控制 8 个 LED。
所需元件:

- Arduino 开发板(如 Uno)
- 74HC595 芯片
- 8 个 LED
- 8 个 220Ω 电阻(用于限流,保护 LED)
- 面包板和连接线
连接方式:
| 74HC595 引脚 | Arduino 引脚 | 功能说明 |
|---|---|---|
| VCC | 5V | 电源正极 |
| GND | GND | 电源负极 |
| DS | Pin 11 | 串行数据输入 (MOSI) |
| SH_CP | Pin 13 | 移位寄存器时钟 (SCK) |
| ST_CP | Pin 10 | 存储寄存器时钟 / 锁存 (SS/CS) |
| OE | GND | 输出使能,始终允许输出 |
| MR | 5V | 主复位,禁止复位,保持工作状态 |
| Q0 - Q7 | LED + 电阻 | 连接到 8 个 LED 的阳极(阴极接地) |
| Q7' | (悬空) | 如果只有一个芯片,此引脚不用 |
连接示意图:
Arduino 74HC595 LEDs
+-----+ +-----+ +-----+
5V o----| VCC |<----------| VCC | | K |
GND o----| GND |----------| GND |----------| (-) |
| | | | | A |
Pin 11 o-| D11 |----------| DS | | (+) |
Pin 13 o-| D13 |----------| SH_CP| +-----+
Pin 10 o-| D10 |----------| ST_CP|
| | | OE |-----------> GND
| | | MR |-----------> 5V
+-----+ | Q0 |-->[R220]--->| (+) |
| ... | | (-) |
| Q7 |-->[R220]--->| (+) |
| Q7' | | (-) |
+-----+ +-----+
注意:[R220] 代表 220Ω 电阻, 和 代表 LED 的阳极和阴极。
C 语言程序 (Arduino IDE)
下面是完整的 Arduino C 语言程序,程序将实现一个简单的流水灯效果。
使用 shiftOut() 函数(最简单、推荐)
Arduino 的 shiftOut() 函数已经为我们封装了所有底层时序操作,是驱动 74HC595 最简单的方法。
/*
* 74HC595 流水灯程序 (使用 shiftOut 函数)
* 功能:控制连接到 74HC595 的 8 个 LED 实现流水灯效果。
*/
// 定义连接到 74HC595 的引脚
const int dataPin = 11; // 74HC595 的 DS (数据引脚)
const int latchPin = 10; // 74HC595 的 ST_CP (锁存引脚)
const int clockPin = 13; // 74HC595 的 SH_CP (时钟引脚)
void setup() {
// 将三个控制引脚设置为输出模式
pinMode(dataPin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop() {
// --- 流水灯效果 ---
// 从 0x01 (00000001) 开始,左移 7 次,再右移 7 次
byte ledPattern = 0x01;
// 向左移动 ( 0b00000001 -> 0b00000010 -> ...)
for (int i = 0; i < 8; i++) {
// 1. 将锁存引脚拉低,准备发送数据
digitalWrite(latchPin, LOW);
// 2. 发送数据
// MSBFIRST 表示最高位在前 (0x01 会点亮 Q0)
shiftOut(dataPin, clockPin, MSBFIRST, ledPattern);
// 3. 将锁存引脚拉高,将数据“锁存”并输出到 LED
digitalWrite(latchPin, HIGH);
// 短暂延时,观察效果
delay(200);
// 左移一位,点亮下一个 LED
ledPattern = ledPattern << 1;
}
// 向右移动 ( 0b10000000 -> 0b01000000 -> ...)
for (int i = 0; i < 8; i++) {
// 1. 将锁存引脚拉低,准备发送数据
digitalWrite(latchPin, LOW);
// 2. 发送数据
// MSBFIRST 表示最高位在前 (0x80 会点亮 Q7)
shiftOut(dataPin, clockPin, MSBFIRST, ledPattern);
// 3. 将锁存引脚拉高,将数据“锁存”并输出到 LED
digitalWrite(latchPin, HIGH);
// 短暂延时,观察效果
delay(200);
// 右移一位,点亮上一个 LED
ledPattern = ledPattern >> 1;
}
}
手动模拟时序(理解底层原理)
如果你想更深入地理解 74HC595 的工作原理,可以不使用 shiftOut() 函数,而是手动用 digitalWrite() 和 delayMicroseconds() 来模拟时序。
/*
* 74HC595 流水灯程序 (手动模拟时序)
* 功能:与上面相同,但通过直接操作引脚来理解 shiftOut 的内部逻辑。
*/
const int dataPin = 11; // DS
const int latchPin = 10; // ST_CP
const int clockPin = 13; // SH_CP
// 手动实现一个移位函数,模拟 shiftOut
void myShiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) {
// bitOrder: MSBFIRST (最高位在前) 或 LSBFIRST (最低位在前)
for (int i = 0; i < 8; i++) {
if (bitOrder == MSBFIRST) {
// 从最高位开始发送
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
} else {
// 从最低位开始发送
digitalWrite(dataPin, !!(val & (1 << i)));
}
// 产生一个时钟上升沿
digitalWrite(clockPin, HIGH);
delayMicroseconds(1); // 短暂延时
digitalWrite(clockPin, LOW);
delayMicroseconds(1); // 短暂延时
}
}
void setup() {
pinMode(dataPin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop() {
byte ledPattern = 0x01;
// 左移
for (int i = 0; i < 8; i++) {
digitalWrite(latchPin, LOW);
myShiftOut(dataPin, clockPin, MSBFIRST, ledPattern);
digitalWrite(latchPin, HIGH);
delay(200);
ledPattern <<= 1;
}
// 右移
for (int i = 0; i < 8; i++) {
digitalWrite(latchPin, LOW);
myShiftOut(dataPin, clockPin, MSBFIRST, ledPattern);
digitalWrite(latchPin, HIGH);
delay(200);
ledPattern >>= 1;
}
}
代码详解
setup() 函数
void setup() {
pinMode(dataPin, OUTPUT);
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
这个函数非常简单,它只是将我们定义的三个控制引脚(dataPin, latchPin, clockPin)设置为输出模式,以便 Arduino 能够向它们发送高低电平信号。
loop() 函数
这是程序的主循环,它不断地执行流水灯效果。
-
digitalWrite(latchPin, LOW);- 作用:将锁存引脚拉低。
- 原因:这是“准备发送数据”的信号,当
ST_CP为低电平时,74HC595 的输出端(Q0-Q7)会保持上一次锁存的状态,不会因我们正在发送新数据而闪烁。
-
shiftOut(dataPin, clockPin, MSBFIRST, ledPattern);- 作用:这是核心的数据发送函数。
dataPin: 数据从哪个引脚发送。clockPin: 时钟信号从哪个引脚发送。MSBFIRST: 数据发送顺序。MSBFIRST表示“Most Significant Bit First”,即最高位(最左边的一位)先发送。ledPattern是0b10000000,它会先发送1,再发送 7 个0,这样最终锁存后,Q7输出高电平,点亮最后一个 LED。ledPattern: 你要发送的 8 位数据,你可以用二进制0b00000001或十六进制0x01来表示。
-
digitalWrite(latchPin, HIGH);- 作用:将锁存引脚拉高。
- 原因:这是“数据已发送完毕,请更新输出”的信号,当
ST_CP从低电平跳变到高电平时,74HC595 内部会将刚刚移位进来的 8 位数据从“移位寄存器”复制到“存储寄存器”,并立刻在 Q0-Q7 引脚上并行输出。这一步是让所有 LED 同时改变状态的关键。
-
ledPattern = ledPattern << 1;- 作用:将
ledPattern的二进制表示向左移动一位。 - 原因:这是实现“流水灯”效果的核心。
0x01(二进制00000001)左移一位后变成0x02(二进制00000010),再左移一位变成0x04(00000100),依此类推,这样每次循环,只有一个高电平在“流动”。
- 作用:将
如何级联多个 74HC595
级联非常简单,可以控制更多 LED,假设你想控制 16 个 LED,需要两个 74HC595。
硬件连接变化:
- 第一个芯片 (Master): 连接方式不变。
- 第二个芯片 (Slave):
- 它的
DS引脚连接到 第一个芯片的Q7'引脚。 - 它的
SH_CP和ST_CP引脚并联到 第一个芯片的对应引脚。 - 它的
VCC,GND,OE,MR连接方式与第一个芯片相同。
- 它的
软件逻辑变化: 你需要将两个芯片的数据合并成一个 16 位的变量,然后一次性发送。
-
合并数据:假设你想控制第一个芯片的 LED1 和第二个芯片的 LED9。
- 第一个芯片的数据:
data1 = 0b00000001; - 第二个芯片的数据:
data2 = 0b00000001; - 合并后的 16 位数据:
uint16_t allData = (data1 << 8) | data2;// 结果是0b0000000100000001
- 第一个芯片的数据:
-
修改发送逻辑:你需要修改
shiftOut的调用,使其发送 16 位数据。shiftOut函数本身不支持 16 位,所以你需要手动循环两次。
// 在 loop() 中替换原来的 shiftOut 调用 digitalWrite(latchPin, LOW); // 先发送第二个芯片的数据(在高位) shiftOut(dataPin, clockPin, MSBFIRST, (allData >> 8)); // 再发送第一个芯片的数据(在低位) shiftOut(dataPin, clockPin, MSBFIRST, allData); digitalWrite(latchPin, HIGH);
注意顺序:因为数据是先通过第一个芯片,溢出”到第二个芯片,所以你必须先发送高位芯片的数据,再发送低位芯片的数据。
希望这份详细的指南能帮助你完全理解和使用 74HC595!
