MC74HC165A与PIC18LF26K22实现高效数字输入扩展

MC74HC165APIC18LF26K22数字输入扩展
于 2026-07-04 13:40:18 修改
·本内容遵循CC 4.0 BY-SA版权协议

1. 项目背景与核心器件选型

在工业控制和嵌入式系统设计中,我们经常需要处理大量数字输入信号。传统方案要么需要占用大量微控制器IO口,要么需要复杂的扩展电路设计。MC74HC165A这款8位并行输入/串行输出移位寄存器,配合PIC18LF26K22这款高性能微控制器,可以优雅地解决这个问题。

MC74HC165A的主要特性包括:

  • 工作电压范围:2V至6V
  • 典型传播延迟:13ns(VCC=4.5V时)
  • 8位并行数据输入
  • 串行数据输出
  • 级联能力(可扩展至任意位数)

选择PIC18LF26K22作为主控的原因在于:

  1. 丰富的外设资源:内置SPI、I2C、UART等通信接口
  2. 宽电压工作范围(1.8V-5.5V)
  3. 低功耗特性(运行模式下最低可达32μA/MHz)
  4. 充足的IO资源(26个通用IO引脚)

2. 硬件电路设计与连接

2.1 基本电路连接

MC74HC165A与PIC18LF26K22的标准连接方式如下:

MC74HC165A引脚 PIC18LF26K22连接 功能说明
VCC 3.3V或5V 电源正极
GND GND 地线
SH/LD RC0 加载/移位控制
CLK SCK(RC3) 时钟信号
QH SDI(RC4) 串行数据输出
SER 悬空或接下一级的QH 级联输入

提示:在实际布线时,建议在VCC和GND之间放置0.1μF的去耦电容,距离芯片不超过1cm。

2.2 级联扩展设计

当需要读取更多输入时,可以采用级联方式:

  1. 将第一片的QH连接到第二片的SER
  2. 所有芯片的SH/LD和CLK并联
  3. 第二片的QH连接到第三片的SER,以此类推

级联后的总输入位数 = 8 × 级联芯片数量

3. 软件实现与寄存器配置

3.1 PIC18LF26K22 SPI模块初始化

C
// SPI主模式初始化
void SPI_Init() {
TRISC3 = 0; // SCK输出
TRISC4 = 1; // SDI输入
TRISC5 = 0; // SDO输出
SSPCON1 = 0b00100010; // SPI主模式,时钟=Fosc/64
SSPSTAT = 0b01000000; // 数据采样在中间,时钟上升沿发送
}

3.2 数据读取函数实现

C
unsigned long read_shift_registers(int chip_count) {
unsigned long data = 0;
// 加载并行数据
LATAbits.LATA0 = 0; // SH/LD拉低
__delay_us(1);
LATAbits.LATA0 = 1; // SH/LD拉高
// 读取串行数据
for(int i=0; i<chip_count*8; i++) {
LATAbits.LATA1 = 0; // CLK拉低
data <<= 1;
data |= PORTBbits.RB0; // 读取QH
LATAbits.LATA1 = 1; // CLK拉高
__delay_us(1);
}
return data;
}

4. 实际应用中的优化技巧

4.1 抗干扰设计

  1. 输入信号滤波:

    • 在每个输入引脚添加100nF电容到地
    • 串联100Ω电阻作为限流保护
  2. 布线注意事项:

    • 时钟线尽量短,避免与其他高频信号平行走线
    • 使用星型接地,避免地环路干扰

4.2 性能优化

  1. 提高读取速度:
C
// 将时钟分频改为Fosc/16
SSPCON1 = 0b00100001;
  1. 中断驱动方式:
C
// 配置中断
PIE1bits.SSPIE = 1; // 使能SPI中断
INTCONbits.PEIE = 1; // 使能外设中断
INTCONbits.GIE = 1; // 使能全局中断

5. 典型应用场景与故障排查

5.1 工业控制面板应用

在一个32键控制面板的实现中:

  1. 使用4片MC74HC165A级联
  2. 每8个输入为一组,连接8个按钮
  3. 通过中断方式检测按键变化

5.2 常见问题排查

现象 可能原因 解决方案
读取数据全为0 SH/LD信号未正确加载 检查SH/LD连接和时序
数据位错位 时钟极性配置错误 调整SSPSTAT.CKE位
部分位不稳定 输入信号未滤波 添加RC滤波电路
级联数据错误 级联顺序接反 检查QH到SER的连接

6. 进阶应用:与其它外设的集成

6.1 配合LCD显示

可以将读取的开关状态实时显示在字符LCD上:

C
void display_switches(unsigned long state) {
lcd_goto(1,1);
for(int i=0; i<32; i++) {
lcd_putch((state & (1UL<<(31-i))) ? '1' : '0');
if((i+1)%8 == 0) lcd_putch(' ');
}
}

6.2 与无线模块通信

通过nRF24L01发送开关状态:

C
void send_switch_data() {
unsigned long switch_state = read_shift_registers(4);
nrf_send((uint8_t*)&switch_state, 4);
}

在实际项目中,我发现这种设计方案特别适合需要大量数字输入但IO资源有限的场景。通过合理级联MC74HC165A,我曾经在一个项目中实现了128个开关状态的读取,而仅占用主控芯片的3个IO口。关键在于:

  1. 严格遵循时序要求
  2. 做好电源去耦
  3. 对长线传输的信号进行适当终端匹配

对于需要更高速度的应用,可以考虑使用74HC165的改进型号74VHC165,其传播延迟可缩短至6ns。另外,如果系统中有多个这类扩展输入,可以采用片选信号来分别控制,进一步节省IO资源。