Tuesday, 15 October 2013 23:27

Arduino通过74HC595扩展IO

Written by
Rate this item
(0 votes)

 

74HC595是一个价格廉宜的8位移位寄存器,通过3个数据引脚(STCP, SHCP, DS),可以控制几乎无限量的输出。

DS是一个串行数据输入端,每当时钟输入(SHCP)上升沿到来时DS引脚当前电平值在移位寄存器中会移一位,连续进行8次同样的动作,就可以完成全部(Q0至Q7)移位。最后当STCP(Latch)上升沿到来时,移位寄存器的值将会被锁定在存储器里,并从Q0至Q7引脚输出。

Arduino UNO只有14+6个数字输出,如果需要更多的输出,其中之一的方法就是通过74HC595来取得更多的输出。 

74HC595 Shift Register

Arduino IDE包含了一个SHIFTOUT()功能,可以很方便的控制74HC595移位寄存器。以下是一个8通道跑马灯例子。

const byte COL_COUNT = 8;
//array to hold the data
unsigned char sequence[COL_COUNT] = {B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000};
//unsigned char sequence[COL_COUNT] = {1, 2, 4, 8, 16, 32, 64, 128};
//unsigned char sequence[COL_COUNT] = {0x01, 0x02, 0x04, 0x8, 0x10, 0x20, 0x40, 0x80};
//Define which pins will be used for the shift register control
//can be any digital pin on the Arduino
int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595
void setup() {    
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
void loop() 
{ 
  for (int col = 0; col < COL_COUNT; col++)   
  {
    digitalWrite(latchPin, LOW); //Pull latch LOW to send data
    shiftOut(dataPin, clockPin, MSBFIRST, sequence[col]); //Send the data
    digitalWrite(latchPin, HIGH); // Pull latch HIGH to stop sending data
    delay(200);
  }
}

Circuit diagram

上面例子使用了一个数组(array)以三种不同的方式来保存数据,其中包括二进制,十进制和十六进制。进制之间是没有区别的,它们都是相同的号码,只是写法不一样吧了。

  • 三行使用二进制编写,必须在二进制数的前面加上B符号
  • 第四使用十进制编写
  • 第五使用十六进制编写,必须在十六进制数的前面加上0x符号

 

且看下面代码:

for (int col = 0; col < COL_COUNT; col++)
{
digitalWrite(latchPin, LOW); //Pull latch LOW to send data
shiftOut(dataPin, clockPin, MSBFIRST, sequence[col]); //Send the data
digitalWrite(latchPin, HIGH); //// Pull latch HIGH to stop sending data
delay(200);
}

 

当col是7时,shiftOut()指令将会如下

shiftOut(11, 12, MSBFIRST, sequence[7])
     or
shiftOut(11, 12, MSBFIRST, B10000000) //binary
     or
shiftOut(11, 12, MSBFIRST, 128) //decimal
     or
shiftOut(11, 12, MSBFIRST, 0x80) //hex

ShiftOut()毎次只能移位8位(1字节),这意味着,执行每个ShiftOut()只能发送8位的数据至74HC595移位寄存器。如果想要移位16位,必须执行两次ShiftOut()

 

上面第一个例子使用了一维数组(Single dimension array)来保存8组二进制数据,接下来例子是同样使用一维数组来保存二进制数据,但这次是24组二进制数据。

const byte COL_COUNT = 8;
const byte ROW_COUNT = 3;
 
//array to hold the data
unsigned char sequence[24] = {
B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000,
B00000001, B00000011, B00000111, B00001111, B00011111, B00111111, B01111111, B11111111,
B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111
};
 
//Define which pins will be used for the shift register control
//can be any digital pin on the Arduino
int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595
 
void setup() {    
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
 
void loop() 
{ 
  for (int row = 0; row < ROW_COUNT; row++) 
  {
    for (int col = 0; col < COL_COUNT; col++) 
    {
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, sequence[col + row*COL_COUNT]);
      digitalWrite(latchPin, HIGH);
      delay(200);
    }
  }
}

 

 当然也可以用二维数组(Two dimension array)来完成同样的效果。

const byte COL_COUNT = 8;
const byte ROW_COUNT = 3;
 
//array to hold the data
unsigned char sequence[ROW_COUNT][COL_COUNT] = {
B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000,
B00000001, B00000011, B00000111, B00001111, B00011111, B00111111, B01111111, B11111111,
B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111
};
 
//Define which pins will be used for the shift register control
//can be any digital pin on the Arduino
int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595
 
void setup() {    
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
 
void loop() 
{ 
  for (int row = 0; row < ROW_COUNT; row++) 
  {
    for (int col = 0; col < COL_COUNT; col++) 
    {
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, sequence[row][col]);
      digitalWrite(latchPin, HIGH);
      delay(200);
    }
  }
}

 

把shiftOut()函数从主程序loop()调去另一个程序(procedure)以方便随时呼叫。 

const byte COL_COUNT = 8;
const byte ROW_COUNT = 3;
 
//array to hold the data
unsigned char sequence[ROW_COUNT][COL_COUNT] = {
B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000,
B00000001, B00000011, B00000111, B00001111, B00011111, B00111111, B01111111, B11111111,
B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111
};
 
//Define which pins will be used for the shift register control
//can be any digital pin on the Arduino
int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595
 
int row;
 
void setup() {    
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
 
void loop() 
{ 
    row = 0; col_display(); 
    row = 1; col_display(); 
    row = 2; col_display(); 
    row = 1; col_display(); 
    row = 0; col_display();    
}
 
void col_display()
{
    for (int col = 0; col < COL_COUNT; col++) 
    {
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, sequence[row][col]);
      digitalWrite(latchPin, HIGH);
      delay(200);
    }  
}

 

使用bitshift

上面的例子也是可以使用的bitshift来完成  。请看到下面的例子,它应用了(<<)运算来取得同样的效果,其输出如下:

00000001  00000010  00000100  00001000  00010000  00100000  01000000  10000000 

const byte COL_COUNT = 8;
int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595
 
void setup() {    
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
 
void loop() 
{ 
  for (int col = 0; col < COL_COUNT; col++)   
  {
    int col_data = 1 << col; //bitshift left
    digitalWrite(latchPin, LOW); //Pull latch LOW to send data
    shiftOut(dataPin, clockPin, MSBFIRST, col_data); //Send the data
    digitalWrite(latchPin, HIGH); //Pull latch HIGH to stop sending data
    delay(200);
  }
}

 

使用bitWrite

以下代码使用bitWrite来显示16组二进制输出,每次8通道,分成两次来完全,其输出如下:

00000001  00000011  00000111  00001111  00011111  00111111  01111111  11111111
11111110  11111100  11111000  11110000  11100000  11000000  10000000  00000000 
const byte COL_COUNT = 8;
int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595
 
void setup() {    
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
 
void loop() 
{ 
  int col_data = 0;
  for (int col = 0; col < COL_COUNT; col++)   
  {
    bitWrite(col_data, col, HIGH);
    digitalWrite(latchPin, LOW); //Pull latch LOW to send data
    shiftOut(dataPin, clockPin, MSBFIRST, col_data); //Send the data
    digitalWrite(latchPin, HIGH); //Pull latch HIGH to stop sending data
    delay(200);
  }
 
  for (int col = 0; col < COL_COUNT; col++)   
  {
    bitWrite(col_data, col, LOW);
    digitalWrite(latchPin, LOW); //Pull latch LOW to send data
    shiftOut(dataPin, clockPin, MSBFIRST, col_data); //Send the data
    digitalWrite(latchPin, HIGH); //Pull latch HIGH to stop sending data
    delay(200);
  }  
}

 

控制两颗74HC595移位寄存器
通过74HC595移位寄存器的级联输出端(Daisy chain),同样使用3个数据引脚来连接多个的74HC595以取得更多的输出。由于shiftOut()只能支持8位移,如欲取得16位移(两颗74HC595移位寄存器)的输出,那就必须分两次shiftOut()运行。

const byte COL_COUNT = 8;
unsigned int sequence[COL_COUNT] = {0B0000000100000001, 0B0000001000000011, 0B0000010000000111, 0B0000100000001111, 0B0001000000011111, 0B10000000111111, 0B0100000001111111, 0B1000000011111111};
//unsigned int sequence[COL_COUNT] = {257, 515, 1031, 2063, 4127, 8255, 16511, 33023};
int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595
 
void setup() {    
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
 
void loop() 
{ 
  for (int col = 0; col < COL_COUNT; col++)   
  {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, (sequence[col] >> 8)); //shift out highbyte
    shiftOut(dataPin, clockPin, MSBFIRST,sequence[col]); //shift out lowbyte    
    digitalWrite(latchPin, HIGH);
    delay(200);
  }
}

注意:

  • 必须把unsigned char sequence[COL_COUNT] 更换成 unsigned int sequence[COL_COUNT] 以便配合16位应用
  • 用于16位的二进制写法,在二进数前段必须加一0B符号

上面例子的输出如下:

Seq. First 74HC595 Second 74HC595
1 00000001 00000001
2 00000011 00000010
3 00000111  00000100 
4 00001111  00001000 
5 00011111  00010000 
6 00111111  00100000 
7 01111111  01000000 
8 11111111  10000000

如图所示是其电路图,74HC595有一个Q7S引脚(级联输出端),用来连接下一个74HC595的DS端。

Controlling two 74HC595 shift register 

  

直接端口访问(Direct port access)
使用直接端口访问,代码将会更小,IO操作更快速。更适合用于记忆体不足之微控制器。 

const byte BIT_COUNT = 8;
// latchPin=Digital 8(74HC595 pin 12)
// clockPin=Digital 12(74HC595 pin 11)
// dataPin=Digital 11(74HC595 pin 14)

void setup() {
//PORTB maps to Arduino digital pins 8 to 13
//set bits 0,3,4 high, this will set digital pin 8,11,12 as output & all other pins as input
DDRB=B00011001;
}

void loop() {
for (int col = 0; col < BIT_COUNT; col++) {
PORTB &= ~(1<<0); //set latch pin (bit 0) low, all other pin unchange
int data = 1 << col; //bitshift left to generate required serial data
ShiftOutLSBFIRST(data);
PORTB |= 1<<0; //set latch pin (bit 0) high, all other pin unchange
delay(200);
}
}


void ShiftOutLSBFIRST(int data) {
for(int i = 0; i < BIT_COUNT; i++) {
if (data & (1<<i)) { //LSB first
PORTB |= 1<<3; //set data pin (bit 3) high, all other pin unchange
} else {
PORTB &= ~(1<<3); //set data pin (bit 3) low, all other pin unchange

}

// generate a pulse for SERIAL CLOCK
PORTB &= ~(1 << 4); // Set the clockPin low
PORTB |= (1 << 4); // Set the clockPin high
// it can also use the code below to generate SERIAL CLOCK
// ^= toggle bit, doing this twice to generate a high low pulse
// PORTB ^= 1 << 4; //toogle bit 3, all other pin unchange
// PORTB ^= 1 << 4;
}
}

  • 如果想控制两个75HC595移位寄存器(16位),把BIT_COUNT换成16就行了
  • 如果想使用MSBFIRST,修改if (data & (1<<i)) { 为以下代码
if (data & (0B1000000000000000>>i)) //most significant bit is sent first

 

 

 

Read 13381 times Last modified on Sunday, 12 June 2016 11:49

Leave a comment

Back to Top