74HC595是我接触最早的一个芯片,它可以将8位串行信号转换成8位并行信号,可用于扩展单片机输出引脚。
还有74HC165,8位并行信号转换成8位串行信号,可用于扩展单片机输入引脚。
他俩与单片机的数据交换都是很简单的串行信号,和几根控制线,在用于扩展输入输出引脚的基础上,能不能让他俩符合SPI协议呢?
于是就有了本项目。
74HC595
需要处理的引脚:
SHCP 接收一个输入,内部寄存器移动一位。
DS 输入数据。
STCP 将内部寄存器复制到输出引脚上。
其中STCP是上升沿时生效,正好对应了片选结束时的上升沿,直接接片选CS。
如果STCP不生效,那么SHCP输入也无所谓,不会影响输出,而且我们每次片选会完整覆盖之前的内容,所以,SHCP直接接时钟MCLK。
DS直连MOSI。
于是简简单单结束了。
在最初的设计中,我给时钟加了多余的三态开关,并错误给片选控制三态开关加了非门,但是很奇怪居然跑起来了。
74HC165
需要处理的引脚:
CE:时钟使能,低电平生效。
CP:输出一位,内部寄存器移动一位。
Q7:输出数据。
PL:锁存内部寄存器。
CE直接接片选CS。
CP直接时钟MCLK。
Q7经过三态开关后接MISO,未选中时避免干扰总线。在我最初的设计中我忘记了这里
但PL并不是与边沿有关的,可以认为低电平时会持续复制输入到寄存器内,但我们希望只复制一次。希望片选低电平到来时PL产生一次下降沿。
于是有了这样子的设计:

片选默认高电平,既C3两侧电压相同。
当片选低电平时,CS是突变的,C3两侧电压不可突变,于是拉低PL,产生一个低电平脉冲。
然后电容开始充电,在1nF、10K的配置下,下拉片选后等待10μs再读数据是保守的可用的时间。
似乎CE不需要接片选,我的设计中怕出问题接了,因为未选中时时钟读读也不影响的。
实测,74HC165输入引脚内部是没有上拉下拉电阻的,悬空就是悬空。
测试
我595和165都串了两个,共16位,并生成随机数,自己输出自己输入。但是只接了4位的线。
void loop()
{
uint8_t num = random() & 0b1111;
d595.setBatch(1, num);
d595.update();
d165.update();
uint8_t read = d165.getBuffer()[1] & 0b1111;
Serial.print("num: ");
Serial.print(num);
Serial.print(",read: ");
Serial.println(read);
if (read != num)
{
Serial.println("读错了!!!");
}
}
遇到的问题比我预料的多多,问题基本都出在写驱动代码上,程序还要加油呀┭┮﹏┭┮
于是这样一个用来扩展IO的方案做好啦~