
1. 为什么需要并行输入扩展在现代嵌入式系统设计中我们经常会遇到一个尴尬的局面主控芯片的GPIO引脚数量有限但外设需求却在不断增加。以STM32F103RC为例这款性价比极高的Cortex-M3芯片虽然功能强大但其GPIO数量在面对复杂控制系统时仍显捉襟见肘。我在去年设计一个工业控制面板时就深有体会需要同时监测32个机械开关状态而STM32F103RC的可用GPIO只有48个除去通信接口、显示驱动等必要功能后留给开关检测的引脚所剩无几。这时候并行输入扩展芯片就成了救命稻草。MC74HC165A作为经典的8位并行输入转串行输出移位寄存器能以极低成本实现GPIO扩展。通过级联多个74HC165理论上可以无限扩展输入通道当然实际受限于时序和系统响应要求。这种方案相比直接使用GPIO扩展器IC如PCA9555有以下优势成本低廉74HC165单价通常不到1元人民币电路简单仅需3个控制信号CLK, SH/LD, DATA兼容性强标准SPI接口几乎所有MCU都能驱动响应快速在10MHz时钟下读取8个开关状态仅需0.8μs2. MC74HC165A核心特性解析2.1 引脚功能与电气特性拆开一颗MC74HC165A你会发现这个16脚DIP封装的芯片内部结构相当精妙。其关键引脚包括SH/LD第1脚移位/装载控制低电平时并行装载输入数据高电平时允许移位CLK第2脚时钟输入上升沿触发数据移位QH第9脚串行数据输出MSB优先/QH第10脚反相串行输出较少使用SER第15脚串行数据输入用于级联扩展A-H第3-6,11-14脚8位并行输入电气参数方面特别要注意VCC范围2V至6V与3.3V的STM32完美兼容输入高电平最小值3.15V VCC5V与STM32对接时建议加电平转换最大时钟频率36MHz VCC4.5V典型功耗80μA静态电流2.2 工作时序深度剖析理解74HC165的关键在于掌握其工作时序。我绘制了以下典型操作序列装载阶段采样输入拉低SH/LD引脚至少35ns典型值此时并行输入A-H的状态被锁存到内部寄存器移位阶段读取数据拉高SH/LD引脚在CLK上升沿数据从QH依次移出MSB优先每个时钟周期移出1位共需8个时钟读取完整字节关键提示在STM32的3.3V系统下建议将CLK频率控制在5MHz以内以确保可靠通信。我曾因使用10MHz时钟导致数据错位最终通过示波器捕获发现是上升时间不足所致。3. STM32硬件设计要点3.1 典型应用电路设计下图展示了STM32F103RC与74HC165的标准连接方式----- PA4 | | 1 SH/LD PA5 | | 2 CLK PA6 | | 9 QH 3.3V| | 15 SER GND | | -----实际设计中必须注意上拉电阻所有未使用的并行输入引脚应通过10kΩ电阻上拉去耦电容每个74HC165的VCC引脚需要100nF陶瓷电容级联连接前一级的QH接下一级的SER共用CLK和SH/LD线长控制时钟信号走线应尽量短超过5cm需考虑终端匹配3.2 电平转换方案当系统中有5V器件时必须进行电平转换。我的项目中使用的是BSS138 MOSFET方案74HC165侧上拉电阻接5VSTM32侧通过BSS138转换成本约0.3元/通道比专用电平转换芯片便宜80%4. 软件驱动实现4.1 基于HAL库的驱动代码以下是经过生产验证的驱动程序核心片段#define HC165_SH_LD_PIN GPIO_PIN_4 #define HC165_CLK_PIN GPIO_PIN_5 #define HC165_DATA_PIN GPIO_PIN_6 uint8_t HC165_ReadByte(void) { uint8_t value 0; // 装载并行数据 HAL_GPIO_WritePin(GPIOA, HC165_SH_LD_PIN, GPIO_PIN_RESET); delay_us(1); HAL_GPIO_WritePin(GPIOA, HC165_SH_LD_PIN, GPIO_PIN_SET); // 移位读取 for(uint8_t i0; i8; i) { value 1; if(HAL_GPIO_ReadPin(GPIOA, HC165_DATA_PIN)) value | 0x01; HAL_GPIO_WritePin(GPIOA, HC165_CLK_PIN, GPIO_PIN_SET); delay_us(0.1); HAL_GPIO_WritePin(GPIOA, HC165_CLK_PIN, GPIO_PIN_RESET); } return value; }4.2 性能优化技巧通过实测发现几个关键优化点使用GPIO端口寄存器直接操作比HAL库快20倍#define HC165_PORT GPIOA #define HC165_SH_LD (14) #define HC165_CLK (15) #define HC165_DATA (16) void HC165_FastRead(uint8_t *buf, uint8_t count) { HC165_PORT-BRR HC165_SH_LD; // 拉低SH/LD __NOP(); __NOP(); // 约35ns延时 HC165_PORT-BSRR HC165_SH_LD; // 拉高SH/LD for(uint8_t j0; jcount; j) { uint8_t val 0; for(uint8_t i0; i8; i) { val 1; if(HC165_PORT-IDR HC165_DATA) val | 1; HC165_PORT-BSRR HC165_CLK; // 上升沿 HC165_PORT-BRR HC165_CLK; // 下降沿 } buf[j] val; } }对于级联多芯片的情况采用DMASPI硬件方案可进一步提升效率配置SPI为主机模式MSB优先将SH/LD信号连接到SPI的NSS引脚使用DMA自动接收数据5. 典型问题排查指南5.1 数据错位问题症状读取的数据位与物理开关状态不对应 排查步骤确认SH/LD信号有足够低电平时间示波器测量50ns检查时钟信号质量上升时间20ns验证级联顺序是否正确第一级的QH接第二级的SER检查PCB布局是否有信号串扰5.2 信号抖动处理在工业环境中我遇到开关抖动导致误触发的问题。解决方案硬件方案在并行输入引脚加RC滤波典型值R1kΩ, C100nF软件方案实现去抖动算法#define DEBOUNCE_TIME 20 // ms uint8_t HC165_ReadDebounced(void) { static uint32_t last_time 0; static uint8_t last_state 0; static uint8_t stable_state 0; uint32_t now HAL_GetTick(); uint8_t current HC165_ReadByte(); if(current ! last_state) { last_time now; last_state current; } else if((now - last_time) DEBOUNCE_TIME) { stable_state current; } return stable_state; }6. 进阶应用实例6.1 64通道输入扩展系统在我的一个自动化测试设备项目中需要监测64个光电传感器状态。设计方案如下级联8个74HC165成本总计约8元使用STM32的SPI1接口驱动硬件连接SPI1_SCK 接所有165的CLKSPI1_MISO接第一级的QHPA4作为NSS信号控制SH/LD读取流程拉低PA4装载数据启动SPI接收8字节64位数据自动存储在接收缓冲区6.2 与矩阵键盘的结合应用将74HC165用于4x4矩阵键盘扫描可节省7个GPIO连接4列线到165的并行输入使用4个GPIO控制行线扫描时依次激活每行通过165读取列状态相比传统矩阵扫描方案IO占用从8个降至5个通过实际项目验证这套方案在降低硬件复杂度的同时键盘响应速度仍能保持在10ms以内完全满足人机交互需求。