▪ 基本信息
在我们的单片机应用系统中,常常会遇到 I/O 口不够的情况。譬如说接有外部 RAM 而且要求有 16 个以上的按键,8 位数码管以上的显示。而且还不包括其它的外围器件。这时整个系统的 I/O 资源就很吃紧了。系统的扩展性也不好。这时我们就需要考虑对单片机的 I/O 进行扩展了。
虽然专门的 I/O 扩展芯片市场上也有不少,但对于我们一般的应用,没有必要整的那么复杂。用一些简单的移位寄存器芯片一样可以实现我们的目标。下面我们首先来认识一下 74HC164 这款芯片。这款芯片的作用是把串行输入的数据并行输出。注意,它没有锁存功能,在允许输出的情况下,每一个时钟的上升沿,数据依次从最低位移向最高位。因此,在做数码管的输出显示的时候会出现拖影的想象,在设计此电路时要注意考虑此情况。
▪ 引脚定义
针脚 | 别名 | 说明 |
DSA DSB | A B | 数据输入端,数据通过这两个输入端之一串行输入;任一输入端可以用作高电平使能端,控制另外一个输入端的数据输入。当其中任意一个为低电平,则禁止新数据输入;当其中有一个为高电平,则另一个就允许输入数据。因此两个输入端或者连接在一起,或者把不用的输入端接高电平,一定不要悬空。 |
Q0~Q7 | 数据输出端。 | |
CP | CLK | 时钟输入端。CP每次有低变高时,数据右移一位,输入到 Q0,Q0是两个数据输入端的逻辑与,它将上升时钟沿之前保持一个建立时间的长度。 |
MR | CLR | 复位清除端,低电平时,其它所有输入端都无效,同时所有输出端均为低电平。 |
GND | 接地端 | |
VCC | 电源端,接 +5V 电源 |
▪ 应用说明
这里我们以 74HC164 驱动 LED 灯来进行说明。
当时钟信号(CP)从低电平变为高电平的时候将 DSA(B) 输入的一位数据输出到 Q0,当时钟第二次由低电平变为高电平的时候将 Q0 的数据移动到 Q1,新的数据依旧保存在 Q0。依此类推,每一个时钟周期中都有一个串行数据输入到 Q0,而其他的数据则不断往高位移动直到所有数据传输结束。如果不再有时钟周期输入,则这些数据将暂存在输出端。
备注:发送一个字节,先输入数据位最终将在Q7口输出,最后输入的数据位将在Q0口输出
如果需要有更多的输出端口,可以把多个74HC164串联起来用。串联的方法如图2所示:上一个芯片的 Q7 连接到下一个芯片的 DSA 和 DSB,以此类推理论是可以无限级联。
在驱动 LED 方面,可以 74HC164 Q0~Q7 可以直接加电阻串联 LED,但是为了增加灵活性适配各种型号的灯,这里我们采用 74HC164 驱动三极管方式,原理图如下:
备注:时钟引脚由低到高的上升沿时间不用太长,为ns级的,不需要使用延时函数
/**
* 74HC164 发送数据
* 该函数为 74HC164 发送字节的程序,该程序是先发送的是最低位
* 备注:发送一个字节,先输入数据位最终将在Q7口输出,最后输入的数据位将在Q0口输出
*
* 数据引脚为(第1脚+第2脚合并为数据引脚),第9脚为复位,通常直接接在VCC上
* 当有多片 74HC164 串联时,只有多次调用该发送程序,先发的字节将会自动溢出到下一个 74HC164
*/
void HC164_SendByte( u8 byte )
{
...
// 发送字节数据
for( i = 0; i < 8; i++ ){
// 取字节最低位
dat = byte & 0x01;
// 发送字节位
// 时钟脚上升沿一次,74HC164 会从其数据脚读取一位数据
GPIO_WriteLow(clockPort, clockPin);
dat ? GPIO_WriteHigh(dataPort, dataPin) : GPIO_WriteLow(dataPort, dataPin);
GPIO_WriteHigh(clockPort, clockPin);
// 将发送的字节右移1位
byte >>= 1;
}
}
备注:优先发送数据字节的低位或者高位没有强制规定,只要处理能正常处理正确即可
缺陷
由于 74HC164 不带锁存器功能,也就是说在每移一位数据都会实时反应在输出口上,这样会导致输出口有不必要的电平变化,虽然非常短暂但是,但是有些情况下这是不允许发生的,如果对时序逻辑有要求的话。
而在上述的例子中,如果我们写一个 “跑马灯” 的程序并运行,就会非常明显的感受 LED 会有拖影。为了解决这个问题,我们可以加大三极管基级的电阻,通过增大阻值减少电流的方式减弱 LED 拖影。但是也可以使用带有锁存功能到 74HC595 芯片,具体参考《扩展IO口:移位寄存器 74HC595(含电路和程序)》