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); } }
上面例子使用了一个数组(array)以三种不同的方式来保存数据,其中包括二进制,十进制和十六进制。进制之间是没有区别的,它们都是相同的号码,只是写法不一样吧了。
- 第三行使用二进制编写,必须在二进制数的前面加上B符号
- 第四行使用十进制编写
- 第五行使用十六进制编写,必须在十六进制数的前面加上0x符号
且看下面代码:
for (int col = 0; col < COL_COUNT; col++) |
当col是7时,shiftOut()指令将会如下
shiftOut(11, 12, MSBFIRST, sequence[7]) |
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通道,分成两次来完全,其输出如下:
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端。
直接端口访问(Direct port access)
使用直接端口访问,代码将会更小,IO操作更快速。更适合用于记忆体不足之微控制器。
const byte BIT_COUNT = 8; void setup() { void loop() {
} // generate a pulse for SERIAL CLOCK |
- 如果想控制两个75HC595移位寄存器(16位),把BIT_COUNT换成16就行了
- 如果想使用MSBFIRST,修改if (data & (1<<i)) { 为以下代码
if (data & (0B1000000000000000>>i)) //most significant bit is sent first |