树莓派的GPIO接口数目有限,驱动一个步进电机需要占用4个, 一个Nokia 5110液晶也要占4个, 传感器输入至少需要一个,多玩几个外设后接口就不够用了。如果接口可以复用就可以让树莓派驱动更多的外设了,本文讨论如何使用74HC595集成电路芯片来扩展树莓派的I/O接口。
芯片介绍
SN74HC595N是德州仪器公司生产的集成电路芯片,是一个8位串行输入变串行输出或并行输出移位寄存器,具有高阻关断,高电平和低电平三态输出。在IO扩充上,可以最多串联15片,也就是高达120个IO扩充。
(注意到芯片上的小凹槽了吗,拿芯片的时候以这个为参考物就不会搞反了)
接口的常用命名方式有以下两种:
接口代号(编号) | 说明 | 接口代号(编号) | 说明 |
---|---|---|---|
Q7’(9) | serial data output | QH’ (9) | serial data output |
MR (10) | Master Reset (Active Low) | SRCLR (10) | Shift register CLeaR |
SH_CP (11) | shift register clock input | SRCLK (11) | Shift Register CLocK input |
ST_CP (12) | storage register clock input | RCLK (12) | storage Register CLocK input |
OE (13) | output enable input (Active Low) | OE (13) | Output Enable |
DS (14) | serial data input | SER (14) | SERial data input |
Qx (15,1-7) | data output | Qx (15,1-7) | data output |
控制流程
如果要在8个引脚输出01010101
- 将Pin 14(DS, SER)置为高电平(1);
- 将Pin 11 (SH_CP, SRCLK))做高低电平切换,形成一个脉冲信号,这个信号会将数据从移位寄存器C1移动到下一个移位寄存器C2,。。。
- 接着将Pin 14设为低电平(0),再将Pin 11做1->0的脉冲变化,将数据继续往下移,依次类推直到8位都输入完成;
- 将Pin 12(ST_CP, RCLK)做1->0的脉冲,将8位数据一次并行输出。
如果要串联多片,由上一片的Pin 9接到下一片的Pin 14即可,这样输入16 bit后,再向Pin 12输入一个1->0的脉冲,16 bit会并行输出。
如果要一次清除所有数据,将Pin 10设为低电平后,再向Pin 12输入一个1->0的脉冲即可;
Pin 13还有高阻关断的第三态输出功能。
下面我们使用一片74HC595来同时控制8个发光二极管的状态,只需要占用树莓派的3个GPIO;否则的话,则需要占用8个。如果需要同时控制16个发光二极管,则可以通过串联两个74HC595来实现。
材料
电路图
引脚连接
- 596 Pin 14 -> Raspberry Pi GPIO4
- 596 Pin 12 -> Raspberry Pi GPIO5
- 596 Pin 11 -> Raspberry Pi GPIO6
代码
#include <wiringPi.h>
#include <stdio.h>
int SER = 4;
int RCLK = 5;
int SRCLK = 6;
unsigned char LED[8]={0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
void SIPO(unsigned char byte);
void pulse(int pin);
void init() {
pinMode(SER, OUTPUT);
pinMode(RCLK, OUTPUT);
pinMode(SRCLK, OUTPUT);
digitalWrite(SER, 0);
digitalWrite(SRCLK, 0);
digitalWrite(RCLK, 0);
}
void delayMS(int x) {
usleep(x * 1000);
}
int main (void)
{
if (-1 == wiringPiSetup()) {
printf("Setup wiringPi failed!");
return 1;
}
init();
int i;
while(1) {
for(i = 0; i < 8; i++)
{
SIPO(LED[i]);
pulse(RCLK);
delayMS(50);
printf(" i = %d", i);
}
printf("\n");
delayMS(500); // 500 ms
for(i = 7; i >= 0; i--)
{
SIPO(LED[i]);
pulse(RCLK);
delayMS(50);
printf(" i = %d", i);
}
delayMS(500); // 500 ms
}
usleep(1000);
digitalWrite(RCLK, 1);
}
void SIPO(unsigned char byte)
{
int i;
for (i=0;i<8;i++)
{
digitalWrite(SER,((byte & (0x80 >> i)) > 0));
pulse(SRCLK);
}
}
void pulse(int pin)
{
digitalWrite(pin, 1);
digitalWrite(pin, 0);
}
编译执行上面的代码后可以看到LED从左到有一次依次点亮后灭掉,再反向点亮一遍,循环执行,有点像钟摆的效果。
参考链接
- http://baike.baidu.com/view/1309513.htm
- http://ruten-proteus.blogspot.com/2012/11/io-74hc595-ic.html
- http://en.wikipedia.org/wiki/Charlieplexing