74HC595 C语言程序如何实现数据移位输出?

99ANYc3cd6
预计阅读时长 26 分钟
位置: 首页 C语言 正文

74HC595 移位寄存器简介

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

74hc595 c语言程序
(图片来源网络,侵删)

主要优点:

  • 节省 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。

所需元件:

74hc595 c语言程序
(图片来源网络,侵删)
  • 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() 函数

这是程序的主循环,它不断地执行流水灯效果。

  1. digitalWrite(latchPin, LOW);

    • 作用:将锁存引脚拉低。
    • 原因:这是“准备发送数据”的信号,当 ST_CP 为低电平时,74HC595 的输出端(Q0-Q7)会保持上一次锁存的状态,不会因我们正在发送新数据而闪烁。
  2. shiftOut(dataPin, clockPin, MSBFIRST, ledPattern);

    • 作用:这是核心的数据发送函数。
    • dataPin: 数据从哪个引脚发送。
    • clockPin: 时钟信号从哪个引脚发送。
    • MSBFIRST: 数据发送顺序MSBFIRST 表示“Most Significant Bit First”,即最高位(最左边的一位)先发送。ledPattern0b10000000,它会先发送 1,再发送 7 个 0,这样最终锁存后,Q7 输出高电平,点亮最后一个 LED。
    • ledPattern: 你要发送的 8 位数据,你可以用二进制 0b00000001 或十六进制 0x01 来表示。
  3. digitalWrite(latchPin, HIGH);

    • 作用:将锁存引脚拉高。
    • 原因:这是“数据已发送完毕,请更新输出”的信号,当 ST_CP 从低电平跳变到高电平时,74HC595 内部会将刚刚移位进来的 8 位数据从“移位寄存器”复制到“存储寄存器”,并立刻在 Q0-Q7 引脚上并行输出。这一步是让所有 LED 同时改变状态的关键。
  4. ledPattern = ledPattern << 1;

    • 作用:将 ledPattern 的二进制表示向左移动一位。
    • 原因:这是实现“流水灯”效果的核心。0x01(二进制 00000001)左移一位后变成 0x02(二进制 00000010),再左移一位变成 0x0400000100),依此类推,这样每次循环,只有一个高电平在“流动”。

如何级联多个 74HC595

级联非常简单,可以控制更多 LED,假设你想控制 16 个 LED,需要两个 74HC595。

硬件连接变化:

  • 第一个芯片 (Master): 连接方式不变。
  • 第二个芯片 (Slave):
    • 它的 DS 引脚连接到 第一个芯片的 Q7' 引脚。
    • 它的 SH_CPST_CP 引脚并联到 第一个芯片的对应引脚
    • 它的 VCC, GND, OE, MR 连接方式与第一个芯片相同。

软件逻辑变化: 你需要将两个芯片的数据合并成一个 16 位的变量,然后一次性发送。

  1. 合并数据:假设你想控制第一个芯片的 LED1 和第二个芯片的 LED9。

    • 第一个芯片的数据:data1 = 0b00000001;
    • 第二个芯片的数据:data2 = 0b00000001;
    • 合并后的 16 位数据:uint16_t allData = (data1 << 8) | data2; // 结果是 0b0000000100000001
  2. 修改发送逻辑:你需要修改 shiftOut 的调用,使其发送 16 位数据。shiftOut 函数本身不支持 16 位,所以你需要手动循环两次。

// 在 loop() 中替换原来的 shiftOut 调用
digitalWrite(latchPin, LOW);
// 先发送第二个芯片的数据(在高位)
shiftOut(dataPin, clockPin, MSBFIRST, (allData >> 8)); 
// 再发送第一个芯片的数据(在低位)
shiftOut(dataPin, clockPin, MSBFIRST, allData);
digitalWrite(latchPin, HIGH);

注意顺序:因为数据是先通过第一个芯片,溢出”到第二个芯片,所以你必须先发送高位芯片的数据,再发送低位芯片的数据

希望这份详细的指南能帮助你完全理解和使用 74HC595!

-- 展开阅读全文 --
头像
C语言如何连接并操作MySQL数据库?
« 上一篇 03-05
dede如何添加自定义属性?
下一篇 » 03-05

相关文章

取消
微信二维码
支付宝二维码

目录[+]