上海极制信息科技有限公司

 找回密码
 立即注册
搜索
热搜: 活动 培训 资料
查看: 2089|回复: 0

通过74HC595扩展Arduino UNO的IO

[复制链接]

39

主题

62

帖子

1287

积分

版主

Rank: 7Rank: 7Rank: 7

积分
1287
发表于 2016-8-16 12:56:55 | 显示全部楼层 |阅读模式
本帖最后由 jizhi01 于 2016-8-16 13:10 编辑

74HC595是一个价格廉宜的8位移位寄存器,通过3个数据引脚(STCP, SHCP, DS),可以控制几乎无限量的输出。
DS是一个串行数据输入端,每当时钟输入(SHCP)上升沿到来时,DS引脚当前电平值在移位寄存器中会移一位,连续进行8次同样的动作,就可以完成全部(Q0至Q7)移位。最后当STCP(Latch)上升沿到来时,移位寄存器的值将会被锁定在存储器里,并从Q0至Q7引脚输出。
Arduino UNO只有14+6个数字输出,如果需要更多的输出,其中之一的方法就是通过74HC595来取得更多的输出。
Arduino UNO只有14+6个数字输出,如果需要更多的输出,其中之一的方法就是通过74HC595来取得更多的输出。
                                                                                    
        
Arduino IDE包含了一个SHIFTOUT()功能,可以很方便的控制74HC595移位寄存器。以下是一个8通道跑马灯例子。
  1. const byte COL_COUNT = 8;
  2. //array to hold the data
  3. unsigned char sequence[COL_COUNT] = {B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000};
  4. //unsigned char sequence[COL_COUNT] = {1, 2, 4, 8, 16, 32, 64, 128};
  5. //unsigned char sequence[COL_COUNT] = {0x01, 0x02, 0x04, 0x8, 0x10, 0x20, 0x40, 0x80};
  6. //Define which pins will be used for the shift register control
  7. //can be any digital pin on the Arduino
  8. int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
  9. int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
  10. int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595
  11. void setup() {   
  12.   pinMode(latchPin, OUTPUT);
  13.   pinMode(clockPin, OUTPUT);
  14.   pinMode(dataPin, OUTPUT);
  15. }
  16. void loop()
  17. {
  18.   for (int col = 0; col < COL_COUNT; col++)   
  19.   {
  20.     digitalWrite(latchPin, LOW); //Pull latch LOW to send data
  21.     shiftOut(dataPin, clockPin, MSBFIRST, sequence[col]); //Send the data
  22.     digitalWrite(latchPin, HIGH); // Pull latch HIGH to stop sending data
  23.     delay(200);
  24.   }
  25. }
复制代码

上面例子使用了一个数组(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组二进制数据。
  1. const byte COL_COUNT = 8;
  2. const byte ROW_COUNT = 3;

  3. //array to hold the data
  4. unsigned char sequence[24] = {
  5. B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000,
  6. B00000001, B00000011, B00000111, B00001111, B00011111, B00111111, B01111111, B11111111,
  7. B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111
  8. };

  9. //Define which pins will be used for the shift register control
  10. //can be any digital pin on the Arduino
  11. int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
  12. int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
  13. int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595

  14. void setup() {   
  15.   pinMode(latchPin, OUTPUT);
  16.   pinMode(clockPin, OUTPUT);
  17.   pinMode(dataPin, OUTPUT);
  18. }

  19. void loop()
  20. {
  21.   for (int row = 0; row < ROW_COUNT; row++)
  22.   {
  23.     for (int col = 0; col < COL_COUNT; col++)
  24.     {
  25.       digitalWrite(latchPin, LOW);
  26.       shiftOut(dataPin, clockPin, MSBFIRST, sequence[col + row*COL_COUNT]);
  27.       digitalWrite(latchPin, HIGH);
  28.       delay(200);
  29.     }
  30.   }
  31. }
复制代码


当然也可以用二维数组(Two dimension array)来完成同样的效果。
  1. const byte COL_COUNT = 8;
  2. const byte ROW_COUNT = 3;

  3. //array to hold the data
  4. unsigned char sequence[ROW_COUNT][COL_COUNT] = {
  5. B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000,
  6. B00000001, B00000011, B00000111, B00001111, B00011111, B00111111, B01111111, B11111111,
  7. B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111
  8. };

  9. //Define which pins will be used for the shift register control
  10. //can be any digital pin on the Arduino
  11. int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
  12. int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
  13. int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595

  14. void setup() {   
  15.   pinMode(latchPin, OUTPUT);
  16.   pinMode(clockPin, OUTPUT);
  17.   pinMode(dataPin, OUTPUT);
  18. }

  19. void loop()
  20. {
  21.   for (int row = 0; row < ROW_COUNT; row++)
  22.   {
  23.     for (int col = 0; col < COL_COUNT; col++)
  24.     {
  25.       digitalWrite(latchPin, LOW);
  26.       shiftOut(dataPin, clockPin, MSBFIRST, sequence[row][col]);
  27.       digitalWrite(latchPin, HIGH);
  28.       delay(200);
  29.     }
  30.   }
  31. }
复制代码

把shiftOut()函数从主程序loop()调去另一个程序(procedure)以方便随时呼叫。
  1. const byte COL_COUNT = 8;
  2. const byte ROW_COUNT = 3;

  3. //array to hold the data
  4. unsigned char sequence[ROW_COUNT][COL_COUNT] = {
  5. B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000,
  6. B00000001, B00000011, B00000111, B00001111, B00011111, B00111111, B01111111, B11111111,
  7. B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111
  8. };

  9. //Define which pins will be used for the shift register control
  10. //can be any digital pin on the Arduino
  11. int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
  12. int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
  13. int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595

  14. int row;

  15. void setup() {   
  16.   Serial.begin(9600);
  17.   pinMode(latchPin, OUTPUT);
  18.   pinMode(clockPin, OUTPUT);
  19.   pinMode(dataPin, OUTPUT);
  20. }

  21. void loop()
  22. {
  23.     row = 0; col_display();
  24.     row = 1; col_display();
  25.     row = 2; col_display();
  26.     row = 1; col_display();
  27.     row = 0; col_display();   
  28. }

  29. void col_display()
  30. {
  31.     for (int col = 0; col < COL_COUNT; col++)
  32.     {
  33.       digitalWrite(latchPin, LOW);
  34.       shiftOut(dataPin, clockPin, MSBFIRST, sequence[row][col]);
  35.       digitalWrite(latchPin, HIGH);
  36.       delay(200);
  37.     }  
  38. }
复制代码

使用bitshift
上面的例子也是可以使用的bitshift来完成  。请看到下面的例子,它应用了左移(<<)运算来取得同样的效果,其输出如下:
00000001  00000010  00000100  00001000  00010000  00100000  01000000  10000000
  1. const byte COL_COUNT = 8;
  2. int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
  3. int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
  4. int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595

  5. void setup() {   
  6.   pinMode(latchPin, OUTPUT);
  7.   pinMode(clockPin, OUTPUT);
  8.   pinMode(dataPin, OUTPUT);
  9. }

  10. void loop()
  11. {
  12.   for (int col = 0; col < COL_COUNT; col++)   
  13.   {
  14.     int col_data = 1 << col; //bitshift left
  15.     digitalWrite(latchPin, LOW); //Pull latch LOW to send data
  16.     shiftOut(dataPin, clockPin, MSBFIRST, col_data); //Send the data
  17.     digitalWrite(latchPin, HIGH); //Pull latch HIGH to stop sending data
  18.     delay(200);
  19.   }
  20. }
复制代码

使用bitWrite
以下代码使用bitWrite来显示16组二进制输出,每次8通道,分成两次来完全,其输出如下:
00000001  00000011  00000111  00001111  00011111  00111111  01111111  11111111

11111110  11111100  11111000  11110000  11100000  11000000  10000000  00000000
  1. const byte COL_COUNT = 8;
  2. int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
  3. int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
  4. int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595

  5. void setup() {   
  6.   pinMode(latchPin, OUTPUT);
  7.   pinMode(clockPin, OUTPUT);
  8.   pinMode(dataPin, OUTPUT);
  9. }

  10. void loop()
  11. {
  12.   int col_data = 0;
  13.   for (int col = 0; col < COL_COUNT; col++)   
  14.   {
  15.     bitWrite(col_data, col, HIGH);
  16.     digitalWrite(latchPin, LOW); //Pull latch LOW to send data
  17.     shiftOut(dataPin, clockPin, MSBFIRST, col_data); //Send the data
  18.     digitalWrite(latchPin, HIGH); //Pull latch HIGH to stop sending data
  19.     delay(200);
  20.   }

  21.   for (int col = 0; col < COL_COUNT; col++)   
  22.   {
  23.     bitWrite(col_data, col, LOW);
  24.     digitalWrite(latchPin, LOW); //Pull latch LOW to send data
  25.     shiftOut(dataPin, clockPin, MSBFIRST, col_data); //Send the data
  26.     digitalWrite(latchPin, HIGH); //Pull latch HIGH to stop sending data
  27.     delay(200);
  28.   }  
  29. }
复制代码

控制两颗74HC595移位寄存器
通过74HC595移位寄存器的级联输出端(Daisy chain),同样使用3个数据引脚来连接多个的74HC595以取得更多的输出。由于shiftOut()只能支持8位移,如欲取得16位移(两颗74HC595移位寄存器)的输出,那就必须分两次shiftOut()运行。
  1. const byte COL_COUNT = 8;
  2. unsigned int sequence[COL_COUNT] = {0B0000000100000001, 0B0000001000000011, 0B0000010000000111, 0B0000100000001111, 0B0001000000011111, 0B10000000111111, 0B0100000001111111, 0B1000000011111111};
  3. //unsigned int sequence[COL_COUNT] = {257, 515, 1031, 2063, 4127, 8255, 16511, 33023};
  4. int latchPin = 8;  //Pin connected to ST_CP(pin 12) of 74HC595
  5. int clockPin = 12; //Pin connected to SH_CP(pin 11) of 74HC595
  6. int dataPin = 11;  //Pin connected to DS(pin 14) of 74HC595

  7. void setup() {   
  8.   pinMode(latchPin, OUTPUT);
  9.   pinMode(clockPin, OUTPUT);
  10.   pinMode(dataPin, OUTPUT);
  11. }

  12. void loop()
  13. {
  14.   for (int col = 0; col < COL_COUNT; col++)   
  15.   {
  16.     digitalWrite(latchPin, LOW);
  17.     shiftOut(dataPin, clockPin, MSBFIRST, (sequence[col] >> 8)); //shift out highbyte
  18.     shiftOut(dataPin, clockPin, MSBFIRST,sequence[col]); //shift out lowbyte   
  19.     digitalWrite(latchPin, HIGH);
  20.     delay(200);
  21.   }
  22. }
复制代码
注意:
  • 必须把unsigned char sequence[COL_COUNT] 更换成 unsigned int sequence[COL_COUNT] 以便配合16位应用
  • 用于16位的二进制写法,在二进数前段必须加一0B符号
上面例子的输出如下:
Seq.First 74HC595Second 74HC595
10000000100000001
20000001100000010
300000111 00000100
400001111 00001000
500011111 00010000
600111111 00100000
701111111 01000000
811111111 10000000
如图所示是其电路图,74HC595有一个Q7S引脚(级联输出端),用来连接下一个74HC595的DS端。


直接端口访问(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
<END>
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|上海极制信息科技有限公司 ( 沪ICP备14016067号

GMT+8, 2018-5-21 01:35 , Processed in 0.139304 second(s), 25 queries .

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表