我再次使用了一个 100uf 的去耦电容,确保在连接时注意极性。
一旦你把它全部连接起来,我们就可以专注于我们将用来完成这项工作的代码。
Arduino & 74HC165 代码我们的代码非常简单,因为它所做的只是读取按钮的状态并在串行监视器上显示结果。但这就是了解如何从按钮和 74HC165 获取数据所需要做的全部工作。
/*
74HC165 Shift Register Demonstration 1
74hc165-demo.ino
Read from 8 switches and display values on serial monitor
DroneBot Workshop 2020
https://dronebotworkshop.com
*/
// Define Connections to 74HC165
// PL pin 1
int load = 7;
// CE pin 15
int clockEnablePin = 4;
// Q7 pin 7
int dataIn = 5;
// CP pin 2
int clockIn = 6;
void setup()
{
// Setup Serial Monitor
Serial.begin(9600);
// Setup 74HC165 connections
pinMode(load, OUTPUT);
pinMode(clockEnablePin, OUTPUT);
pinMode(clockIn, OUTPUT);
pinMode(dataIn, INPUT);
}
void loop()
{
// Write pulse to load pin
digitalWrite(load, LOW);
delayMicroseconds(5);
digitalWrite(load, HIGH);
delayMicroseconds(5);
// Get data from 74HC165
digitalWrite(clockIn, HIGH);
digitalWrite(clockEnablePin, LOW);
byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
digitalWrite(clockEnablePin, HIGH);
// Print to serial monitor
Serial.print("Pin States:\r\n");
Serial.println(incoming, BIN);
delay(200);
}
代码与我们之前的所有代码一样,定义了到 IC 的四个连接。
在设置中,我们初始化串行监视器,然后根据需要设置连接。
在循环中,我们首先向加载引脚写入一个脉冲,这将使其将并行输入中的数据加载到要处理的缓冲区中。
接下来,我们设置 74HC165 准备发送数据,然后使用shiftIn函数获取该数据,首先是 LSB(最低有效位)。我们通过将时钟引脚拉高来完成,这表示我们已经完成了。
最后,我们将结果打印到串行监视器。
加载代码,打开串行监视器并观察输出。马上你就会注意到一些事情。
数据在输出端全部保持高电平,与板上接线相反。按下按钮将使其读数为低,即使这与实际发生的情况相反。
这是因为我们使用的是 74HC165 的取反输出。我们的数据是相反的。
我将在稍后的代码中向您展示如何以正确的方式将其转回来。继续阅读!
我们刚刚使用的示例有许多实际应用,其中一个明显的应用是作为小键盘(尽管有更好的方法来制作大键盘)。对于需要大量开关的项目来说,这是一种有用的设计技巧。
该电路的一个重要应用是将它与 DIP 开关或跳线一起使用,这些开关或跳线只是偶尔设置。您可以使用 74NC165 来减少读取 8 位 DIP 开关所需的连接数量,只需在设置程序中读取它,以便仅在设备通电或复位时读取。
74HC595 和 74HC165 一起使用当然,将所有这些 LED 和开关连接起来而不采取额外的步骤将它们连接在一起将是一种浪费!所以让我们这样做。
74HC595 和 74HC165 连接如果您像我一样在自己的无焊面包板上构建每个演示,那么将它们连接在一起非常简单。
在其中一个演示中将 Arduino 与其面包板断开连接,哪个并不重要。将连接留在面包板上,以便您可以将它们重新连接到另一个 Arduino。您可以将 5 伏和接地连接连接到其他面包板电源轨。
完成后尝试在 Arduino 上运行之前的代码,一切都应该仍然有效。如果某些东西不起作用,请检查您的接线,当您加入项目时,某些东西可能已断开连接 - 这里有很多电线!
测试完所有内容后,就可以查看代码以同时使用 74HC165 和 74HC595。
74HC595 和 74HC165 代码 1由于我们的演示本质上是将两个演示融合在一起,因此我们的代码完全相同。你会看到这个代码和之前的代码有很多相似之处,这并非偶然——其中一些是字面上的剪切和粘贴!
代码的目的是简单地使用 LED 来显示按钮的状态。作为演示,它运行良好。我保证在这之后我们会继续做一些更令人兴奋的事情!
/*
74HC595 & 74HC165 Shift Register Demonstration
74hc595-to-74ch165.ino
Input for 8 pushbuttons using 74HC165
Output to 0 LEDs using 74HC595
DroneBot Workshop 2020
https://dronebotworkshop.com
*/
// Define Connections to 74HC165
// PL pin 1
int load = 7;
// CE pin 15
int clockEnablePin = 4;
// Q7 pin 7
int dataIn = 5;
// CP pin 2
int clockIn = 6;
// Define Connections to 74HC595
// ST_CP pin 12
const int latchPin = 10;
// SH_CP pin 11
const int clockPin = 11;
// DS pin 14
const int dataPin = 12;
void setup () {
// Setup Serial Monitor
Serial.begin(9600);
// 74HC165 pins
pinMode(load, OUTPUT);
pinMode(clockEnablePin, OUTPUT);
pinMode(clockIn, OUTPUT);
pinMode(dataIn, INPUT);
// 74HC595 pins
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop() {
// Read Switches
// Write pulse to load pin
digitalWrite(load, LOW);
delayMicroseconds(5);
digitalWrite(load, HIGH);
delayMicroseconds(5);
// Get data from 74HC165
digitalWrite(clockIn, HIGH);
digitalWrite(clockEnablePin, LOW);
byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
digitalWrite(clockEnablePin, HIGH);
// Print to serial monitor
Serial.print("Pin States:\r\n");
Serial.println(incoming, BIN);
// Write to LEDs
// ST_CP LOW to keep LEDs from changing while reading serial data
digitalWrite(latchPin, LOW);
// Shift out the bits
shiftOut(dataPin, clockPin, LSBFIRST, ~incoming);
// ST_CP HIGH change LEDs
digitalWrite(latchPin, HIGH);
delay(500);
}
我们再次定义两个集成电路的引脚连接。在设置中,我们初始化串行监视器并根据需要设置连接。
循环以我们之前用于从 74HC165 读取按钮值的相同例程开始。我们再次将数据插入一个称为“传入”的 8 位字节中,并在串行监视器上显示其值。
接下来,我们使用之前使用的相同代码将数据写入 74HC595。但是我们对发送到移位寄存器上的数据进行了一项更改。
请记住,我们来自交换机的数据是反转的。如果我们将它发送到 74HC595 它将工作,但 LED 将全部亮起,除非我们按下了按钮。
为了反转数据,当我们在shiftOut函数中使用它时,我们在“传入”变量前面使用“~”符号。波浪号(波浪线)符号反转二进制数据,将每个零变成一,反之亦然。正是我们需要做的。
您还会注意到我们与早期 74HC595 代码不同的一件事是我们首先发送数据 LSB。这与我们从按钮接收它的方式相匹配。首先发送 MSB 会起作用,但 LED 显示会反转。
加载它并尝试一下。
很有趣,不是吗?
好吧,它确实不是,但它确实展示了如何获取并行数据(开关输入),使用移位寄存器将其转换为串行,将其发送到 Arduino,将其发送回第二个移位寄存器并进行转换它再次回到并联状态(LED 输出)。这有点令人兴奋。
如果您不是很兴奋,请不要担心,现在我们有 8 个开关和 8 个 LED,我们可以做其他事情。
74HC595 和 74HC165 代码 2 – 令人兴奋!为了给我们的演示增添一些料,让我们使用八个开关来选择 LED 灯闪烁模式。因为我们有八个开关,所以我们可以选择八个模式。
这是我们如何做到的代码:
/*
74HC595 & 74HC165 Shift Register Demonstration 2
74hc595-to-74ch165-pattern.ino
Input from 8 pushbuttons using 74HC165
Output to 8 LEDs using 74HC595
Select LED pattern using pushbuttons
DroneBot Workshop 2020
https://dronebotworkshop.com
*/
// Define Connections to 74HC165
// PL pin 1
int load = 7;
// CE pin 15
int clockEnablePin = 4;
// Q7 pin 7
int dataIn = 5;
// CP pin 2
int clockIn = 6;
// Define Connections to 74HC595
// ST_CP pin 12
const int latchPin = 10;
// SH_CP pin 11
const int clockPin = 11;
// DS pin 14
const int dataPin = 12;
// Define data array
int datArray[8];
void setup () {
// Setup Serial Monitor
Serial.begin(9600);
// 74HC165 pins
pinMode(load, OUTPUT);
pinMode(clockEnablePin, OUTPUT);
pinMode(clockIn, OUTPUT);
pinMode(dataIn, INPUT);
// 74HC595 pins
pinMode(latchPin,OUTPUT);
pinMode(clockPin,OUTPUT);
pinMode(dataPin,OUTPUT);
}
void loop() {
// Read Switches
// Write pulse to load pin
digitalWrite(load,LOW);
delayMicroseconds(5);
digitalWrite(load,HIGH);
delayMicroseconds(5);
// Get data from 74HC165
digitalWrite(clockIn,HIGH);
digitalWrite(clockEnablePin,LOW);
byte incoming = shiftIn(dataIn, clockIn, LSBFIRST);
digitalWrite(clockEnablePin,HIGH);
// Print to serial monitor
Serial.print("Pin States:\r\n");
Serial.println(incoming, BIN);
// Setup array for LED pattern
switch (incoming) {
case B11111110:
datArray[0] = B11111111;
datArray[1] = B01111110;
datArray[2] = B10111101;
datArray[3] = B11011011;
datArray[4] = B11100111;
datArray[5] = B11011011;
datArray[6] = B10111101;
datArray[7] = B01111110;
break;
case B11111101:
datArray[0] = B00000001;
datArray[1] = B00000010;
datArray[2] = B00000100;
datArray[3] = B00001000;
datArray[4] = B00010000;
datArray[5] = B00100000;
datArray[6] = B01000000;
datArray[7] = B10000000;
break;
case B11111011:
datArray[0] = B10000001;
datArray[1] = B01000010;
datArray[2] = B00100100;
datArray[3] = B00011000;
datArray[4] = B00000000;
datArray[5] = B00100100;
datArray[6] = B01000010;
datArray[7] = B10000001;
break;
case B11110111:
datArray[0] = B10101010;
datArray[1] = B01010101;
datArray[2] = B10101010;
datArray[3] = B01010101;
datArray[4] = B10101010;
datArray[5] = B01010101;
datArray[6] = B10101010;
datArray[7] = B01010101;
break;
case B11101111:
datArray[0] = B10000000;
datArray[1] = B00000001;
datArray[2] = B01000000;
datArray[3] = B00000010;
datArray[4] = B00100000;
datArray[5] = B00000100;
datArray[6] = B00010000;
datArray[7] = B00001000;
break;
case B11011111:
datArray[0] = B11000000;
datArray[1] = B01100000;
datArray[2] = B00110000;
datArray[3] = B00011000;
datArray[4] = B00001100;
datArray[5] = B00000110;
datArray[6] = B00000011;
datArray[7] = B10000001;
break;
case B10111111:
datArray[0] = B11100000;
datArray[1] = B01110000;
datArray[2] = B00111000;
datArray[3] = B00011100;
datArray[4] = B00001110;
datArray[5] = B00000111;
datArray[6] = B10000011;
datArray[7] = B11000001;
break;
case B01111111:
datArray[0] = B10001000;
datArray[1] = B01000100;
datArray[2] = B00100010;
datArray[3] = B00010001;
datArray[4] = B10001000;
datArray[5] = B01000100;
datArray[6] = B00100010;
datArray[7] = B00010001;
break;
default:
break;
}
// Write to LEDs
// Count from 0 to 7
for(int num = 0; num < 8; num )
{
// ST_CP LOW to keep LEDs from changing while reading serial data
digitalWrite(latchPin, LOW);
// Shift out the bits
shiftOut(dataPin,clockPin,MSBFIRST,datArray[num]);
// ST_CP HIGH change LEDs
digitalWrite(latchPin, HIGH);
delay(200);
}
}
正如你所看到的,我再次从之前的所有演示中借用了编码。事实上,这个代码只有一件事不同,那就是允许您选择 LED 模式的 switch-case 语句。
我们使用保存开关值的“传入”字节作为语句的开关。然后我们有八个情况,每个开关按下一个。如果您想允许同时按下两个按钮,您可能可以添加更多按钮,但八个对我来说已经足够了!
在每个情况下,我们用 LED 图案填充datArray阵列,以二进制编写,以便于查看。在每个字节中,“1”表示 LED 点亮,而“0”表示 LED 熄灭。
我在数组中使用了八个元素以使其更容易,但您可以将其增加到您喜欢的任何数字。只需更改数组定义和循环遍历数组元素的 for-next 循环中的数字即可。
我将模式更改之间的延迟设置为 200 毫秒,但您可以更改它。更好的是,尝试将延迟作为每个案例评估中的变量,这样您就可以使模式以不同的速度运行。