Arduino 拓展输出接口

在前面的文章自己打造一台恩尼格玛密码机中,介绍了使用 Arduino Mega 2560 实现一个简易 Enigma 机的方法。这个型号的 Arduino 单片机拥有 50 多个数字 IO,因此可以妥善地处置按键输入,并控制大量的发光二极管(键盘灯)及数码管。
但是,其它型号的 Arduino 就不一定能完成这个任务了 —— 例如 Arduino Leonardo 只有 20 个数字 IO。那么,有没有办法拓展这些输出接口呢?答案是肯定的。借助于移位寄存器,Arduino 可以将串行信号转为并行,以此通过较少的引脚来控制多路输出。

首先我们来看看一看移位寄存器的工作原理。这里涉及到数字电路中 D 触发器的特性。D 触发器在时钟的上升沿触发,触发后其输出 Q 锁定为此时数据输入引脚 D 的状态,直到下一次触发。

在下图所示的电路中,每一个时钟脉冲后,每个 D 触发器都会把输入的数据「送」到下一级的 D 触发器中。

它的时序图如下:

可以看到,如果同步地将串行数据和时钟信号输入,那么在四个时钟脉冲后,Q0,Q1,Q2,Q3 的输出就正好对应输入的串行数据。换言之,这实现了 4 位的串入并出移位寄存器。

同理,使用 8 个 D 触发器,就能够实现 8 位的移位寄存器。一个典型的解决方案是 74HC595 芯片,它配合 Arduino 用起来非常方便:只需要将 ST_CP(锁存),CP(时钟脉冲)和 DS(串行输入)三个引脚接到单片机上,即可控制 8 位并行输出。
如下图所示,这三个引脚分别接到了 Arduino 的 10,9,8 引脚上。此外还需要将 OE 引脚接低电平,MR 引脚接高电平。

程序写起来也很简单,可以使用内置的 shiftOut 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int latchPin = 10; //锁存引脚
int clockPin = 9; //时钟引脚
int dataPin = 8; //数据引脚

void shiftRegisterOut(int data) {
digitalWrite(latchPin, LOW); //将ST_CP口上加低电平让芯片准备好接收数据
shiftOut(dataPin, clockPin, MSBFIRST, data);
digitalWrite(latchPin, HIGH); //将ST_CP这个针脚恢复到高电平
}

void setup() {
// put your setup code here, to run once:
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}

void loop() {
for (int i = 0; i <= 255; i++) {
shiftRegisterOut(i);
delay(10);
}
}

更多的例子可以查看官方文档:Serial to Parallel Shifting-Out with a 74HC595