74hc165引脚图及功能程序


74HC165:并行输入串行输出移位寄存器详解
在数字电子领域,并行输入串行输出(PISO)移位寄存器是一种至关重要的器件,它能够将多个并行输入的数据位转换为串行数据流,从而有效减少微控制器或其他逻辑器件所需的I/O引脚数量。其中,74HC165是CMOS系列中一款非常常用的8位PISO移位寄存器,以其高速度、低功耗和可靠性,在各种数据采集、传感器接口和I/O扩展应用中占据着重要地位。
本章节将深入探讨74HC165的引脚图、各项功能、工作原理、时序分析,并提供基于常见微控制器(如Arduino和STM32)的编程示例,旨在帮助读者全面理解和掌握74HC165的应用。
1. 74HC165 概述与特点
74HC165是一款高速CMOS器件,属于74HC(High-speed CMOS)系列。它继承了CMOS器件低功耗的优点,同时拥有接近LSTTL(Low-power Schottky TTL)器件的速度。其核心功能是将8路并行输入的数据同时载入内部寄存器,然后通过一个时钟脉冲,以串行方式一位一位地将数据移出。这种并行转串行的能力使其成为扩展微控制器输入端口的理想选择。
主要特点包括:
8位并行输入: 可以同时接收8位数据。
串行输出: 数据以串行方式逐位输出。
异步并行载入: 允许在任何时钟周期内载入并行数据,由PL(并行载入)引脚控制。
同步串行移位: 数据的移位与时钟脉冲同步。
高噪声抗扰性: CMOS特性使其对噪声具有较强的抵抗能力。
宽工作电压范围: 通常为2V至6V,适用于多种电源环境。
宽温度范围: 适用于工业和商业应用。
这些特性使得74HC165在按钮阵列扫描、键盘接口、传感器数据采集、多路开关状态监测以及任何需要将大量并行输入转换为串行数据以节省I/O资源的场景中表现出色。
2. 74HC165 引脚图及功能详解
理解74HC165的引脚功能是正确使用它的前提。74HC165通常采用16引脚DIP(双列直插式封装)或SOIC(小外形集成电路封装)等形式。
(注:此处应为74HC165的引脚图,由于我无法直接生成图片,请您自行查找对应的74HC165数据手册以获取准确的引脚图。)
以下是74HC165各引脚的详细功能说明:
2.1. 电源引脚
VCC (Pin 16): 电源正极输入。通常连接到+5V或+3.3V电源。
GND (Pin 8): 接地引脚。连接到电源的负极或电路的公共地。
2.2. 并行输入引脚
D0 - D7 (Pin 15, 14, 13, 12, 11, 10, 9, 7): 这八个引脚是8位并行数据的输入端。当 PL(并行载入) 引脚为低电平(L)时,数据会从这些引脚加载到内部寄存器中。它们通常连接到传感器、开关、按钮或其他需要读取状态的数字信号源。
2.3. 控制引脚
PL (Parallel Load) / SH/LD (Shift/Load) (Pin 1): 并行载入使能引脚。
低电平(L): 激活并行载入功能。当此引脚为低电平,且时钟(CP)处于上升沿时,D0-D7引脚上的并行数据将被加载到内部寄存器中。在某些数据手册中,此引脚可能标记为 overlineSH/LD,表示低电平时是载入(Load),高电平时是移位(Shift)。
高电平(H): 禁止并行载入,允许移位操作。 这个引脚是控制74HC165工作模式的关键,无论是读取并行数据还是进行串行移位,都需要正确设置它。
CP (Clock Pulse) (Pin 2): 时钟输入引脚。这是移位寄存器的主时钟信号。
上升沿: 在移位模式下(PL为高电平),Q7(串行输出)上的数据会移动到Q6,Q6移动到Q5,以此类推,同时D7(并行输入)上的数据移入Q0。
下降沿: 通常对数据移位没有影响,但在某些应用中可能会被用于特定的同步。 时钟信号的稳定性直接影响数据传输的可靠性。
CE (Clock Enable) / CLK_INH (Clock Inhibit) (Pin 15): 时钟使能/时钟禁止引脚。
低电平(L): 允许时钟(CP)信号通过,移位寄存器正常工作。
高电平(H): 禁止时钟信号通过,即使CP引脚有脉冲,移位寄存器也不会发生移位。 这个引脚可以用来暂停数据移位,或者在多个移位寄存器级联时,对特定的芯片进行时钟控制。这个引脚与CP引脚共同控制移位操作的时序。
2.4. 串行输出引脚
Q7 (Pin 6): 串行数据输出引脚。这是移位寄存器的数据出口,每次时钟脉冲(CP上升沿)后,最先被加载到内部寄存器的数据位会从这里移出。通常连接到微控制器的GPIO引脚,用于接收串行数据。
overlineQ7 (Pin 5): Q7的互补输出引脚。其逻辑状态与Q7相反。这个引脚在某些应用中可能有用,例如当需要反向数据或作为辅助信号时。
3. 74HC165 工作原理
74HC165的工作原理可以分为两个主要阶段:并行数据载入和串行数据移位。
3.1. 并行数据载入
当 PL(并行载入) 引脚被拉低(逻辑L)时,74HC165进入并行载入模式。此时,无论时钟(CP)引脚处于何种状态,D0到D7引脚上的瞬时逻辑电平会被立即捕获并加载到内部的8个D触发器中。这个过程是异步的,这意味着数据的载入不受时钟边沿的严格控制,只要PL为低,数据就会被载入。
重要提示: 为了确保数据的正确载入,在PL引脚从高电平变为低电平,并维持低电平的整个期间,D0-D7上的数据必须保持稳定。一旦PL被拉高,数据就被锁存,并且移位操作开始。
3.2. 串行数据移位
当 PL 引脚被拉高(逻辑H)时,74HC165进入串行移位模式。此时,移位寄存器开始响应 CP(时钟) 引脚的上升沿。
每当CP引脚检测到一个上升沿,内部寄存器中的数据就会向右(从Q0到Q7方向)移动一位。这意味着:
D7引脚上的当前数据(如果CP_INH为低电平且PL为高电平)将移入Q0寄存器。
Q0寄存器中的数据移到Q1。
Q1寄存器中的数据移到Q2。
...
Q6寄存器中的数据移到Q7。
Q7寄存器中的数据将通过Q7引脚输出。
CE(时钟使能) 引脚在移位过程中扮演着重要的角色。如果CE为高电平,即使CP引脚有上升沿,移位操作也会被阻止,内部寄存器的数据状态保持不变。只有当CE为低电平,并且PL为高电平,CP的上升沿才能触发数据移位。
通过连续提供8个时钟脉冲,可以依次从Q7引脚读取完整的8位并行数据。第一个移出的位是D7处的数据(在载入时)。
工作流程总结:
将 PL 拉低,将并行数据(D0-D7)载入到74HC165的内部寄存器中。
将 PL 拉高,使74HC165进入移位模式。
确保 CE 保持低电平,允许时钟通过。
发送一个时钟脉冲(CP引脚产生一个上升沿),第一个数据位(即最初加载的D7位)会出现在 Q7 引脚上。
读取 Q7 引脚上的数据。
重复步骤4和5,发送7个额外的时钟脉冲,每次读取一个数据位,直到所有8位数据都被读取完毕。
4. 时序分析
理解74HC165的时序图对于确保数据传输的正确性至关重要。时序图描述了不同信号之间的时间关系,例如数据建立时间、保持时间、传播延迟等。
4.1. 关键时序参数
t_su (Setup Time): 建立时间。指数据在时钟有效沿到来之前,输入数据必须保持稳定的最短时间。例如,在PL引脚从低电平跳变为高电平之前,并行数据D0-D7必须稳定下来。
t_h (Hold Time): 保持时间。指数据在时钟有效沿到来之后,输入数据必须保持稳定的最短时间。
t_pd (Propagation Delay): 传播延迟。指信号从输入端(如CP或PL)到输出端(如Q7)所需的时间。
4.2. 并行载入时序
当 PL 从高到低电平跳变时,开始并行载入。D0-D7上的数据必须在此之前稳定,并在PL变为高电平之后保持一段时间。CP 的状态在并行载入期间不重要。
4.3. 串行移位时序
当 PL 为高电平且 CE 为低电平时,CP 的上升沿触发数据移位。在CP上升沿到达之前,输入到D7的数据(如果是级联应用)以及内部寄存器的数据必须稳定。Q7输出的数据在CP上升沿后经过一段传播延迟后变为有效。
设计考量:
在实际应用中,需要确保微控制器输出的时钟信号和控制信号满足74HC165的时序要求。例如,如果时钟频率过高,可能导致数据建立时间和保持时间不足,从而引入错误。通常,微控制器的数字I/O口足以满足74HC165的时序要求,但在高速应用中,应查阅数据手册中具体的时序参数。
5. 74HC165 的应用场景
74HC165由于其并行转串行的特性,广泛应用于以下领域:
输入扩展: 最常见的应用是扩展微控制器的输入端口。例如,一个Arduino Uno只有有限的数字输入引脚,但通过一个74HC165可以轻松读取8个按钮或开关的状态,而只需要占用3-4个微控制器的引脚(数据、时钟、载入、可选的时钟使能)。
键盘接口: 在一些简单的键盘或按钮矩阵中,74HC165可以用来扫描行或列,并将按下的键的状态转换为串行数据。
传感器数据采集: 当有多个数字传感器(如光电开关、限位开关等)需要同时监测时,74HC165可以集中采集这些传感器的状态,然后通过串行方式传输给微控制器。
多路开关状态监测: 在工业控制、自动化设备中,需要监测大量开关、继电器或其他数字信号的状态,74HC165可以有效简化布线和I/O设计。
数据总线复用: 在某些数据总线设计中,如果需要将并行数据发送到串行总线,74HC165可以作为中间转换器。
级联应用: 多个74HC165可以级联,以读取更多位的并行数据。例如,两个74HC165可以组成16位并行输入,三个则为24位,以此类推。
6. 74HC165 编程示例
本节将提供基于两种常见微控制器平台——Arduino和STM32——的74HC165编程示例,以展示如何通过代码控制74HC165并读取并行输入数据。
6.1. 硬件连接
在开始编程之前,确保您的74HC165与微控制器正确连接。以下是一个典型的连接方案:
74HC165 引脚 | 对应的微控制器引脚 (示例) | 功能说明 |
VCC | +5V 或 +3.3V | 电源 |
GND | GND | 地 |
D0 - D7 | 连接到需要读取的并行输入源 | 并行输入 |
PL | 数字输出引脚 (例如 Arduino D8) | 载入控制 |
CP | 数字输出引脚 (例如 Arduino D9) | 时钟 |
CE | GND (通常接地使能) | 时钟使能 |
Q7 | 数字输入引脚 (例如 Arduino D10) | 串行数据输出 |
重要提示:
CE引脚: 在大多数简单应用中,可以将CE引脚直接接地(GND),使其始终处于使能状态,从而简化控制。如果需要动态控制时钟,则需要连接到一个微控制器数字输出引脚。
上拉/下拉电阻: 如果您的并行输入D0-D7连接的是不确定状态的传感器或开关,可能需要添加外部上拉或下拉电阻来确保其在未触发时的逻辑状态。例如,如果连接按钮,通常需要上拉电阻。
6.2. Arduino 编程示例
这个示例演示如何使用Arduino Uno读取连接到74HC165的8个开关状态。
Arduino 代码:
C++// 定义连接74HC165的Arduino引脚const int PL_PIN = 8;
// Parallel Load / Shift_Loadconst int CP_PIN = 9;
// Clock Pulseconst int Q7_PIN = 10; // Serial Data Output (Data In for Arduino)void setup() {
// 设置引脚模式
pinMode(PL_PIN, OUTPUT);
pinMode(CP_PIN, OUTPUT);
pinMode(Q7_PIN, INPUT); // Q7是数据输入到Arduino
// 初始化串行通信,用于调试输出
Serial.begin(9600);
Serial.println("74HC165 读取示例");
}void loop() {
byte data = read74HC165(); // 读取74HC165的数据
// 将读取到的数据打印到串口监视器
Serial.print("读取到的数据 (二进制): ");
printByteAsBinary(data);
Serial.println();
delay(500); // 每0.5秒读取一次}// 函数:从74HC165读取8位数据byte read74HC165() {
byte incomingByte = 0; // 1. 启动并行载入:将PL拉低
digitalWrite(PL_PIN, LOW); // 短暂延时以确保PL稳定,虽然HC系列速度很快,但良好的习惯
// delayMicroseconds(1);
// 2. 结束并行载入并进入移位模式:将PL拉高
digitalWrite(PL_PIN, HIGH); // 确保数据稳定后,可以开始移位
// 3. 读取8位数据
// 74HC165的串行输出是最低有效位优先(LSB first),但其内部移位是从D7移出。
// 因此,第一次时钟脉冲移出的是D7,第二次是D6,以此类推。
// 如果你需要LSB优先的字节顺序,需要将接收到的位反转顺序。
// 在这里,我们将读取到的位按照D7, D6, ..., D0的顺序组合成一个字节。
for (int i = 0; i < 8; i++) { // 每次读取一位之前,给一个时钟脉冲
digitalWrite(CP_PIN, LOW); // CP拉低
// delayMicroseconds(1);
digitalWrite(CP_PIN, HIGH); // CP上升沿触发移位
// delayMicroseconds(1); // 留出时间给数据稳定
// 读取Q7引脚上的数据,并将其移入到incomingByte的正确位置
// 最先读到的是最高位 (D7),所以将其放到字节的最高位
if (digitalRead(Q7_PIN) == HIGH) {
incomingByte = incomingByte | (1 << (7 - i)); // 设置对应位为1
} else { // 保持对应位为0(默认就是0,所以这行可以省略,但为了清晰说明)
incomingByte = incomingByte & ~(1 << (7 - i));
}
} return incomingByte;
}// 辅助函数:将字节以二进制形式打印void printByteAsBinary(byte b) { for (int i = 7; i >= 0; i--) {
Serial.print((b >> i) & 0x01);
}
}
代码解释:
引脚定义: 定义了Arduino连接到74HC165的三个控制引脚(PL, CP)和一个数据输入引脚(Q7)。
setup()
函数:将PL和CP引脚设置为输出模式,因为Arduino需要控制它们。
将Q7引脚设置为输入模式,因为Arduino要从这个引脚读取数据。
初始化串口通信,用于调试。
loop()
函数:重复调用
read74HC165()
函数来获取数据。将获取到的字节以二进制形式打印出来。
read74HC165()
函数:digitalWrite(CP_PIN, LOW);
和digitalWrite(CP_PIN, HIGH);
: 生成一个时钟脉冲的上升沿。每次上升沿都会使74HC165内部数据移位一位,并将当前最高位(D7位,首次移位时是最初载入的D7位)通过Q7引脚输出。digitalRead(Q7_PIN)
: 读取Q7引脚的当前状态。incomingByte = incomingByte | (1 << (7 - i));
: 这是将读取到的位组合成一个字节的关键。74HC165的移位顺序是从D7到D0。第一次读取到的是D7,第二次是D6,以此类推。
1 << (7 - i)
会生成一个只有第(7 - i)
位是1的掩码。例如,当i=0
时 (第一次循环),掩码是10000000
(二进制),用于设置incomingByte
的最高位 (bit 7)。当i=7
时 (最后一次循环),掩码是00000001
(二进制),用于设置incomingByte
的最低位 (bit 0)。|
(按位或) 操作用于将读取到的位设置到incomingByte
的相应位置。digitalWrite(PL_PIN, LOW);
: 将PL引脚拉低,触发74HC165将并行输入数据(D0-D7)异步载入到其内部寄存器。digitalWrite(PL_PIN, HIGH);
: 将PL引脚拉高,结束并行载入,使74HC165进入移位模式。循环8次: 为了读取8位数据,需要发送8个时钟脉冲。
printByteAsBinary()
函数: 一个辅助函数,用于将字节数据以二进制字符串的形式打印到串口监视器,方便观察。
6.3. STM32 编程示例 (HAL库)
对于STM32微控制器,我们通常使用HAL库或LL库。这里以HAL库为例,演示如何配置GPIO并读取74HC165的数据。
STM32CubeIDE 配置:
在STM32CubeIDE中,您需要首先配置GPIO引脚。假设您使用以下引脚:
PL_PIN: 例如 PA0 (GPIO_Output)
CP_PIN: 例如 PA1 (GPIO_Output)
Q7_PIN: 例如 PA2 (GPIO_Input)
确保将CP_PIN和PL_PIN配置为推挽输出,Q7_PIN配置为浮空输入或上拉输入。
STM32 HAL库代码 (核心读取函数):
C#include "main.h" // 包含CubeMX生成的头文件#include <string.h> // For strlen#include <stdio.h>
// For sprintf// 定义连接74HC165的GPIO引脚和端口#define PL_GPIO_PORT GPIOA#define PL_GPIO_PIN
GPIO_PIN_0#define CP_GPIO_PORT GPIOA#define CP_GPIO_PIN
GPIO_PIN_1#define Q7_GPIO_PORT GPIOA#define Q7_GPIO_PIN
GPIO_PIN_2// UART句柄,用于printf输出(如果配置了UART)extern UART_HandleTypeDef huart2;
// 假设您的UART2用于调试输出/**
* @brief 从74HC165读取8位并行数据
* @param None
* @retval 读取到的8位数据
*/uint8_t Read_74HC165(void){ uint8_t received_data = 0; // 1. 启动并行载入:拉低PL引脚
HAL_GPIO_WritePin(PL_GPIO_PORT, PL_GPIO_PIN, GPIO_PIN_RESET); // 稍作延时,确保PL引脚稳定
// 仅在非常苛刻的时序要求下考虑,通常对于HC系列不需要微秒级延时
// for(volatile int i=0; i<10; i++);
// 2. 结束并行载入,进入移位模式:拉高PL引脚
HAL_GPIO_WritePin(PL_GPIO_PORT, PL_GPIO_PIN, GPIO_PIN_SET); // 数据现在被锁存,可以开始移位
// 3. 循环8次,读取8位数据
for (int i = 0; i < 8; i++)
{ // 生成一个时钟脉冲的上升沿
HAL_GPIO_WritePin(CP_GPIO_PORT, CP_GPIO_PIN, GPIO_PIN_RESET); // CP拉低
// for(volatile int i=0; i<10; i++); // 短暂延时
HAL_GPIO_WritePin(CP_GPIO_PORT, CP_GPIO_PIN, GPIO_PIN_SET); // CP上升沿触发移位
// for(volatile int i=0; i<10; i++); // 短暂延时,留出数据稳定时间
// 读取Q7引脚的状态
if (HAL_GPIO_ReadPin(Q7_GPIO_PORT, Q7_GPIO_PIN) == GPIO_PIN_SET)
{ // 将读取到的位设置到received_data的正确位置
// 74HC165第一次移出的是D7,所以要放在最高位
received_data |= (1 << (7 - i));
}
} return received_data;
}// 辅助函数:将字节以二进制形式打印(通过UART)void PrintByteAsBinary(uint8_t b) { char buffer[10];
// 8位 + null terminator
for (int i = 0; i < 8; i++) {
buffer[i] = ((b >> (7 - i)) & 0x01) ? '1' : '0';
}
buffer[8] = '