中间的Arduino:输入和输出

96556年

652

19

简介:中间Arduino:输入和输出

关于:我在推特和instagram上更新:@amandaghassaei

继续从我Arduino入门本教程将介绍Arduino的一些更高级的主题,特别是与控制和管理许多输入和输出相关的主题。下节课将介绍如何将Arduino的输入输出连接到MIDI

零件清单:

(1x)arduino uno亚马逊或者你也可以在当地买一辆窝棚电台

(1 x) usb电缆亚马逊

(1x)面包板(这个带跳线)亚马逊

(1 x)跳线亚马逊

(8 x)红色发光二极管Digikey C503B-RCN-CW0Z0AA1-ND

(8 x) 220欧姆电阻Digikey CF14JT220RCT-ND

(1 x) 10 kohm电阻器Digikey CF14JT10K0CT-ND

(1x)Tact按钮Digikey 450 - 1650

(1x)595班次寄存器296 - 1600 - 5 nd Digikey

(1x)红色LED点阵Adafruit的454

第一步:无延迟眨眼()

到目前为止,我们一直在用延迟()功能暂时暂停Arduino草图,使两个Arduino命令之间可以有一点时间。在了眨眼草图,我们使用delay()来设置打开Arduino的时间和关闭它的时间:

//打开LED灯
//等待1000毫秒(1秒)
//关闭LED
延迟(1000); //等一下

有时使用delay()不是一个很好的选项,因为arduino在延迟发生时无法执行任何辅助任务。想象一下,我们想要闪烁LED并使用Delay()同时检测按钮按下按钮:

循环(){

digitalWrite (ledPin、高);
延迟(1000);
digitalWrite(ledPin,LOW);
延迟(1000);
boolean buttonState = digitalRead(7); / /读取数据

在上面的代码中,我们每两秒钟测量一次按钮,所以可能需要两秒钟才能检测到按钮按下,而非常短暂的按下可能根本不会检测到。

米尔斯()让我们可以控制事件发生的时间,而不需要在草图中添加停顿。每次在Arduino草图中调用millis()时,它将返回自Arduino打开以来的毫秒数。


运行以下代码,看看millis()是如何工作的:


//使用Arduino millis()记录时间void setup() {Serial.begin(9600);} void loop() {unsigned long currentMillis = millis();以currentMillis);}

下面是如何使用millis()来闪烁LED而不使用delay()。


//blink led without delay() int ledPin = 7;int ledState =低;/ /领导的当前状态无符号长timeOfLastLedEvent = 0; / / LED上一次更新int intervalON = 1000; / /多长时间我们希望领导继续int intervalOFF = 500; / /多长时间我们希望导致远离空虚setup () {pinMode (ledPin、输出);digitalWrite (ledPin ledState);} void loop() {unsigned long currentMillis = millis();if (ledState == LOW){//如果LED已经关闭if (currentMillis - timeOfLastLedEvent > intervalOFF){//经过足够的时间digitalWrite(ledPin,}} else{//如果LED已经开了if (currentMillis - timeOfLastLedEvent > intervalON){digitalWrite(ledPin, LOW);ledState =低;timeOfLastLedEvent = currentMillis;}}}

上面的草图介绍了一些新东西:

无符号长是另一种数据类型吗int布尔).unsigned long就像int,但更大,我会解释......每个数据类型都需要在arduino的内存中的一定量的空间,以及arduino frees为给定变量的空间量决定了min和max值变量可以存储。例如,如果您尝试执行类似的事情,int的范围为-32,768至32,767:

int myVariable = 100,000;

你最终会在代码中发现一个非常奇怪的错误。这可能看起来像是一个任意的范围,但它来自于这样一个事实,即int需要在Arduino的内存中占用16位空间,而使用16位二进制,您可以存储从0到(2^16-1)= 65535的数字。但人们认为int也应该能够存储负数,所以16位数字中的一位用于存储符号(正负),其余15位存储值:2^15 = 32768。包括0,我们得到的范围是- 32768到32767。另一种数据类型称为徽章int不存储符号,所以它得到0到65535的范围,我之前计算过,但你不能存储一个负数在一个有符号的int。

当需要使用大于65535或小于-32768的数字时,我们使用名为.Long在Arduino的内存中分配了32位的空间。2的32次方= 4,294,967,296,在0附近居中,得到一个范围:-2,147,483,648到2,147,483,647。Unsigned long,就像Unsigned int一样,总是正的,所以它们的范围从0到4,294,967,295。

没有数据类型来存储数字比长,所以如果你需要存储数量超过4294967295,你必须提出一个不同的方式来存储它(前9位可能在另一个一个数和最后九?)。这个限制对于millis()函数有一些有趣的结果。由于millis返回的是无符号的long,并且它总是以毫秒为单位计算,所以一旦millis()达到这个值,它实际上会重置为零:

4,294,967,295女士

= 4294967秒

= 49.71天

如果您使用Millis()并且您计划在未延长的时间段内延长或重置您的项目运行,您应该注意到这一点。

一个评论数据类型:我们可以使用长时间的或无符号长整当我们申报的密码或其他变量草图到目前为止的示例中,但通常是一个好主意使用最小的数据类型的一个变量,这样你有足够的额外的空间在Arduino的内存为其他事情。在Arduino中,long很少被使用,但是millis()是它们会派上用场的一个很好的例子。

回到草图时,一般的想法是在最后一次存储LED上或关闭LED并与Millis()返回的当前时间进行比较。一旦这两次之间的差异大于某些间隔,您就知道它是时候再次切换了LED。为此,我设置了一些新的存储变量:

INT ledState = LOW; //当前LED的状态
unsigned long timeOfLastLedEvent = 0;//最后一次LED更新
int intervalON = 1000;//我们希望LED灯亮多长时间
int intervalOFF = 500;//我们希望LED保持关闭多长时间

在loop()中有一串逻辑检查是否已经经过了足够的时间,如果是,切换LED,更新变量“timeOfLastLedEvent”,并切换LED的存储状态。这个逻辑重复了两次,一次是LED高,一次是LED低,下面我将重复低的情况:

if (currentMillis - timeOfLastLedEvent > intervalOFF){//经过了足够的时间

digitalWrite(ledPin, HIGH);//打开
//存储它的当前状态
timeOfLastLedEvent = currentMillis;//更新这个新事件的时间

currentMillis是一个无符号长函数,表示每次Arduino的loop()函数启动时更新的当前时间。(currentMillis - timeOfLastLedEvent)给出LED状态上次改变的时间,我们将此与intervalOFF比较,看看是否到了关闭LED的时间,如果不是,Arduino将继续更新currentMillis并重新检查,直到它的时间。

步骤2:Arduino按钮恢复

继续从按钮推出我在我最后的指示中介绍,我们可以使用millis()来取消按钮而不使用delay():


//按钮按下检测 - 去抖动与米利斯()INT buttonPin = 7;布尔currentState = LOW; // stroage为当前测得的按钮状态布尔lastState = LOW; //用于存储最后的测量按钮的状态的布尔debouncedState = LOW; //去抖按钮状态INT debounceInterval = 20; //等待20毫秒按钮销解决无符号长timeOfLastButtonEvent = 0; //存储上一次按钮状态改变的空隙设置(){pinMode(buttonPin,INPUT); //这一次我们将设置销为INPUT Serial.begin(9600); //初始化串行连接}空隙环(){currentState = digitalRead(buttonPin);无符号长currentTime的单位为毫秒=();如果{timeOfLastButtonEvent = currentTime的(currentState = lastState!);}如果(currentTime的 -  timeOfLastButtonEvent> debounceInterval){//如果有足够的时间已经过去了,如果(currentState = debouncedState!){//如果当前状态,较上次存储抖状态debouncedState = currentState仍然不同; //更新状态去抖//触发事件时,如果(debouncedState == HIGH){Serial.println( “按压”);}其他{Serial.println( “释放”);}}} lastState = currentState; }

在此代码中,我添加了一些新的存储变量:

Boolean DebouncedState =低;
int debounceInterval = 20;
unsigned long timeOfLastButtonEvent = 0;

DebouncedState存储当前的逐个衰败状态,这是我们绝对确定按钮的状态。相比之下,CurrentState和持久存储我们用按钮所做的当前和上次测量,但他们没有告诉我们状态肯定的按钮,因为它们可能受到影响按钮喋喋不休

debounceInterval是MS的量等待键引脚解决之前,我们肯定知道它处于什么状态,我我的最后一个例子我以前用的是1毫秒,现在用的是20毫秒。

timeOfLastButtonEvent类似于上一个示意图中的timeOfLastLedEvent,它给出了一个时间来与currentTime进行比较,这样我们就可以计算从第一次检测到按钮按下已经过去了多少秒。

当currentState不等于lastState时,重置timeOfLastButtonEvent:

如果(currentState!= lastState){

timeOfLastButtonEvent = currentTime的;


经过足够的时间过去,不需要重置timeoflastButtonevent,我们知道该按钮已结算成衰败状态:

currentTime的 - timeOfLastButtonEvent> debounceInterval

然后我们可以更新当前存储的debounce状态,如果它已经改变,如果是,根据新的debounce状态触发一个事件:

if (currentState != debouncedState){

debouncedState =现状后;

if(debouncedstate == high){

serial.println(“按下”);

其他}{

以“发布”);

第三步:移位寄存器

到目前为止,我们已经看到了如何使用Arduino同时控制多个数字输入和输出,但有时我们想要控制的组件比Arduino的引脚更多。在这种情况下,我们可以使用外部集成电路(也称为“芯片”)以扩展Arduino的输入和输出。

转移寄存器是使用逻辑门一次控制多个输入或输出。它们本质上是数字的,就像Arduino上的数字大头针一样——这意味着它们只能读或写0V和5V(低或高)。如果你想要扩展你的模拟输入,那么你需要一个解复用器4051(阅读更多关于如何使用它在这里).在这个Instructable中,我们将查看74HC595移位寄存器(称为“595”),它非常流行,因为它可以将3个Arduino数字输出扩展为8个输出。

595有8个输出引脚标记为Q0-Q7(有时也称为Qa-Qh),它不能从这些引脚读取数据,它们只能用作输出(如果你正在寻找一个移位寄存器与8个输入引脚,检查74年hc165,教程在这里).595由三个连接控制,它们被称为数据引脚、闩锁引脚和时钟引脚。参考上面的流程图,看看如何控制输出引脚(下面重复):

  • 首先,闩锁引脚(在上面的第二个图中标记为“闩锁时钟”)被设置为LOW以禁用输出引脚(标记为“并行数据输出”),这样当我们向595发送新数据时,输出引脚不会改变
  • 接下来,新的数据被发送到595通过脉冲时钟引脚(“移位时钟”)和通过数据引脚(“串行数据输入”)发送每个8个输出状态。Arduino在它的库中有一个方便的函数叫做shiftOut我将在下一步中解释如何使用它。
  • 最后,将锁销设为HIGH。这将你的新数据一次发送到所有的输出引脚(称为并行输出).

步骤4:595和SHIFTOUT

接下来,我们将看一看595的数据表,以找到正确的引脚连接。上面的第一个图像显示了595引脚连接。595上有16个引脚,标记为1-16。注意芯片一侧的半圆标记,1号引脚总是位于芯片的左侧。其余的引脚按逆时针方向围绕芯片编号。

第二张图片显示了pin名,按pin号排序,并附有简短的描述。引脚1-7和15是输出Q0-Q7,暂时离开那些引脚不连接。引脚8是接地引脚,连接到Arduino接地。引脚9是一个串行数据输出,这是用来连接到其他595的菊花链.菊花链接允许您只使用三个Arduino的数字引脚驱动16个或更多输出。在本教程的范围之外有点超出,但您可以了解更多关于它的信息在这里.由于我们不会使用PIN 9,我们可以将其留下来(也称为“浮动”)。引脚10是主复位,当该引脚变低时,它会导致移位寄存器重置 - 丢失我们之前可能已经存储的任何数据。我们现在不想要此功能,因此将重置连接到5V以防止重置发生。引脚11是时钟输入或“时钟引脚”,将此连接到Arduino数字引脚7.引脚12是存储寄存器时钟输入或“闩锁销”,将其连接到Arduino数字引脚6.引脚13是输出使能引脚,当它较低时它允许595将数据发送到其输出,我们希望将此引脚连接到地面。引脚14是串行数据输入,将其连接到Arduino数字引脚5.引脚16是芯片的电源,将其连接到5V。您的电路应如图3所示。

现在连接一个LED和电阻接地到每个595的8个输出引脚。你的电路现在应该看起来像图4。现在设置595高输出引脚将打开相应的LED,设置它低将关闭LED。上传以下代码:


//设置595 state int clockPin = 7;int latchPin = 6; / /输出int dataPin = 5;byte numberToDisplay = 154;void setup(){//所有到595的连接都是输出pinMode(latchPin, OUTPUT);pinMode (clockPin、输出);pinMode (dataPin、输出);} void loop(){//首先设置锁存引脚低,这样我们就可以在不中断输出的情况下移动数据digitalWrite(latchPin, low);//将数据移出移位//设置锁存引脚高发送数据到输出引脚digitalWrite(latchPin, high); }

这段代码引入了一个名为字节, byte就像int,但是因为bytes只需要8位内存,所以它们只存储0到255(2^8 = 256)之间的数字。

剩下的代码很简单,除了下面这行:

shiftOut(dataPin, clockPin, LSBFIRST, numberToDisplay);

在这一行中,Arduino使用595的数据和时钟引脚将数字154 (numberToDisplay的当前值)发送到移位寄存器。数字154包含595所有8个引脚的状态:

154转换为二进制的10011010

如果你看一下LED的状态,你会看到连接到Q0的LED是亮的,Q1和Q2是关的,Q3和Q4是亮的,Q5是关的,Q6是亮的,Q7是关的。因此,LED遵循与二进制数字相同的模式,1表示亮的LED, 0表示关的LED。


现在尝试其他数字,数字15是二进制的是00001111,你可以在谷歌上通过输入#然后短语“to binary”(它吐出的数字将以0b开始,忽略这一部分,并获取最后8位)找到其他十进制到二进制的转换。记住,我们只能将8位的二进制数字(8位)发送到移位寄存器,因为它只有8个输出引脚,所以numberToDisplay的值必须在0到255之间。

现在尝试将参数LSBFIRST更改为MSBFIRST,您应该看到led的顺序相反,这个变量设置了我们将二进制数发送到595的方向:LSBFIRST表示“最低有效位优先”,MSBFIRST表示“最高有效位优先”。


为了让它更有趣,试试下面的方法:


int clockPin = 7;int latchPin = 6; / /输出int dataPin = 5;void setup(){//所有到595的连接都是输出pinMode(latchPin, OUTPUT);pinMode (clockPin、输出);pinMode (dataPin、输出);} void loop() {for (byte numberToDisplay=0;numberToDisplay<256;numberToDisplay + +) {digitalWrite (latchPin、低);//将数据移出移位//设置锁存引脚高发送数据到输出引脚digitalWrite(latchPin, high); delay(500); } }

现在你已经把led变成了二进制计数器:

步骤5:Arduino控制LED矩阵

接下来我们将看看如何使用Arduino来控制一个8x8的LED矩阵,一个由64个LED组成的网格。我们将使用的8 × 8矩阵有16个引脚连接到它:8个引脚连接矩阵每列中所有led的正引线,另外8个引脚连接矩阵每列中所有led的接地引线。这使我们可以控制每个LED分别处理。请看上面第二幅图中的图表。想象所有列都接地,除了列8,它连接(通过限流电阻)到5V。没有图像显示除第一行接地外所有行都接5V在此场景中唯一亮起的LED位于第1行和第1列。

如图1所示,将LED矩阵放置在面包板中。使用限流电阻将列(见第二幅图中的引脚编号)连接到5V,并使用常规跳线将列连接到地。你应该看到整个LED显示屏都亮了起来。现在试着从地面拔下一行,并将其连接到5V,那一行中的每个LED都会关闭。试着将一根柱子连接到地面,柱子里的每一个LED都会关闭。

现在拔掉所有从排引脚到地的连接,只留下一个,这样就只有一排led亮了。不要把这些列连接到5V,而是把它们连接到Arduino(仍然把限流电阻放在电路中)。请看第三张图片,更好地了解这应该是什么样子。下面是这些列应该如何连接到Arduino:

列1 - Arduino A0(模拟引脚0)

第2列 - Arduino A1

第3栏- Arduino A2

第4列- Arduino A3

第5列- Arduino A4

第6栏- Arduino A5

第7列- Arduino D2(数字引脚2)

第8列- Arduino D3

运行以下代码:


void setup(){//set pins A0-A6 as outputs for (int pinNum=A0;pinNum
        


唯一有点古怪这个代码就是我们使用的模拟引脚用作数字输出,这是通过Arduino的允许。模拟引脚可以作为数字输入和输出,但它们具有作为模拟输入以及所添加的功能。我们将使用许多的Arduino的引脚在这个例子中(共16个),所以只好由布线了一些模拟引脚的开始。另一件事,我特意留下引脚0和1没有重视他们。Arduino的使用这些引脚通过USB通信,并且有时具有东西连接到引脚0和1的抑制与板进行编程的能力。

你应该会看到连接到地面的那一排led亮起的图案。一个LED亮,一个灭,一个亮,一个灭…等等。这个模式如图#3所示。

现在,从LED矩阵中移除与地面的连接,并将另一行电线连接到地面。你应该在不同的行上看到相同的模式(图4)。在下一步中,我们将使用Arduino选择性地接地每一行。

首先再试一件事,改变led的开关模式,以下是我所做的:


void setup(){//set pins A0-A6 as outputs for (int pinNum=A0;pinNum
        

输出被示出上述的最后一个图像英寸

步骤6:LED矩阵复用

现在将LED矩阵的所有接地引脚连接到Arduino的6-13引脚上。这里是引脚连接:

第1行 - Arduino D6(数字引脚6)

第2行- Arduino D7

第3行 - Arduino D8

第4行- Arduino D9

第5行 - Arduino D10

第6行- Arduino D11

第7行- Arduino D12

第8行 - Arduino的D13

并运行以下代码:


void setup(){//设置引脚6-13作为输出并初始化HIGH(因此所有led都关闭开始)for (int pinNum=6;pinNum<14;pinNum++){pinMode(pinNum, OUTPUT);digitalWrite (pinNum、高);} //set pins A0-A6 as outputs for (int pinNum=A0;pinNum
        


你应该看到相同的模式的led点亮一行(第二张图片),因为每一行都是一个接一个接地。现在尝试减少延迟,模式将在行之间移动得越来越快。现在完全删除延迟,你应该看到所有的行点亮(似乎是)同一时间(第三张图片)。下面是一个视频演示(这一次,使用不同的模式来点亮每一行,我很快就会解释更多):

这就是所谓的多路复用.即使它看起来我们同时照亮了许多行的LED,我们也知道我们实际上是一个接一个地照明每一行,但我们正在这么快地这样做,我们欺骗了我们的眼睛思考这一切都是同时发生的。多路复用是有用的,任何时候都希望使用相对较少的针相对较少的东西来控制很多东西。我们可以单独使用每个LED,而不是将它们复用并显着减少成本和麻烦。

现在试着将不同的模式发送到不同的行:


void setup(){//set pinNum 6-13 as outputs and initialize HIGH for (int pinNum=6;pinNum<14;pinNum++){pinMode(pinNum, OUTPUT);digitalWrite (pinNum、高);} //set pins A0-A6 as outputs for (int pinNum=A0;pinNum
        

一开始缓慢运行这段代码,我们看到一行被发送了一个模式,而下一行被发送了一个不同的模式,这在矩阵的所有行中交替进行。我是这样做的:

if (pinNum%2==1){//是pinNum是奇数

被称为“modulo”,它类似于除法,但不是返回pinNum/2,而是返回该操作的余数。如果pinNum = 6 pinNum%2 = 0,因为2能整除6。如果pinNum = 7,则pinNum%2 = 1。这给了我一个简单的方法来计算哪些行是偶数哪些是奇数。使用这些信息,我可以向交替的行发送不同的模式。

现在尝试从代码中删除延迟。你应该看到一个棋盘图案出现在LED矩阵上(第四张图片)。通过将不同的模式发送到每一行,并在每一行中单独循环,您可以精确地控制哪些led是开着的,哪些是关着的。试试以下:


void setup(){//set pinNum 6-13 as outputs and initialize HIGH for (int pinNum=6;pinNum<14;pinNum++){pinMode(pinNum, OUTPUT);digitalWrite (pinNum、高);} //set pins A0-A6 as outputs for (int pinNum=A0;pinNum
        

这段代码只会将连接到引脚8的行设置为A5 HIGH。这只会点亮矩阵中的一个LED(第五张图片)。

步骤7:发送字节到多路LED矩阵

到目前为止,我们用来将数据发送到LED的代码编写起来有点尴尬。它包括显式地为连接到列的每个Arduino引脚分配HIGH或LOW状态。如果我们想让矩阵的8行显示不同的模式,我们将不得不编写大量的代码。这里有一种组织事物的方法:


void setup(){//set pinNum 6-13 as outputs and initialize HIGH for (int pinNum=6;pinNum<14;pinNum++){pinMode(pinNum, OUTPUT);digitalWrite (pinNum、高);} //set pins A0-A6 as outputs for (int pinNum=A0;pinNum
        

还记得我们如何使用0到255(一个字节)之间的数字来设置连接到595的8个led的状态吗?现在我已经添加了一个名为setStates()的函数,它让我们使用一个字节在LED矩阵的每一行中设置8个LED的状态。setStates所做的第一件事是将所有连接到LED矩阵列的引脚设置为LOW,以关闭任何可能打开的LED。然后它使用。检查8位字节的每个二进制数&运算符;如果任何数字为1,则设置相应的引脚高。

上面的代码使用数字56设置连接到数字引脚8的行。在二进制中,56表示为:

00111000

LED输出结果如上图所示,你可以看到二进制数字中的每一个1对应着矩阵中一个发光的LED。

接下来尝试在LED矩阵中对每一行进行编程,以显示它所附的数字引脚的编号:


void setup(){//set pinNum 6-13 as outputs and initialize HIGH for (int pinNum=6;pinNum<14;pinNum++){pinMode(pinNum, OUTPUT);digitalWrite (pinNum、高);} //set pins A0-A6 as outputs for (int pinNum=A0;pinNum
        

输出显示上述第二图像英寸

步骤8:使用数组存储和设置LED矩阵的状态

在最后一步中,我们看到了如何使用字节来简化设置LED矩阵中每一行的状态的过程。现在我们来看看在一个数组.数组是一个我们可以存储相关变量集合的地方,在本例中,我将使用一个数组来存储每一行矩阵的状态。因为我们用一个字节表示矩阵中每一行的状态,有8行,我需要一个8字节的数组来存储LED矩阵中所有64个LED的状态。下面是创建数组的方法

byte ledStates[8] = {0, 15, 0, 0, 0, 84, 0, 0};

我已经用一组字节初始化了数组,我加入了一些非零字节,看看它们如何显示在LED矩阵上。下面是如何使用数组:


byte ledStates[8] = {0, 15, 0, 0, 0, 84, 0, 0};void setup(){//set pinNum 6-13 as outputs and initialize HIGH for (int pinNum=6;pinNum<14;pinNum++){pinMode(pinNum, OUTPUT);digitalWrite (pinNum、高);} //set pins A0-A6 as outputs for (int pinNum=A0;pinNum
        

为了获得存储在数组中的变量,你可以使用以下语法:

arrayName [variableIndex]

其中variableIndex是变量在数组中的位置。例如:

ledStates [0] = 0

ledStates [1] = 15

因为数组中的第一个(index = 0)元素是0,第二个(index = 1)元素是15。

因为我不再在for循环中遍历pinNums,所以我创建了一个helper函数,它在迭代器变量“I”和连接到感兴趣的行的Arduino引脚之间进行转换:

INT getPinNumForLEDIndex(INT指数){

返回索引+ 6;

尝试更改数组ledStates中的字节,以查看它们如何影响矩阵的输出。也试着在草图运行时改变存储在ledStates中的变量,使用以下语法:

ledStates [indexNum] = newValue

你也可以使用以下方式写的字节来设置led的状态:

B11011011

B让Arduino知道它应该期待一个二进制数字,然后接下来的8个数字是你想要显示的8位二进制数字。这使得在LED矩阵上设计2D图案变得更容易一些。尝试使用这个数组:

字节LEDSTATES [8] = {B0111100,B01000010,B10110101,B10000101,B10000101,B10110101,B010000101,1110101,B01000010,B0111100};

步骤9:用芯片控制LED矩阵

到目前为止,这个电路消耗了大量的Arduino引脚。如果您需要将其他东西连接到您的Arduino,尝试使用595代码和LED矩阵代码,使用更少的Arduino引脚来控制矩阵(提示-将595的8个输出连接到LED矩阵的8行8列)。你甚至可以使用两个595的,一个用于控制行,另一个用于控制列。需要注意的一件事是,Arduino引脚或595都不能提供足够的电流来驱动一排全亮度的led,所以你可能想要使用类似于TPIC6B595(高功率移位寄存器)如果你担心亮度。

同样的想法(多路复用)也可以用于控制输入网格,比如按钮。我不会在这篇文章中详细介绍,但你可以找到更多相关信息在这里(多路复用按钮与多路复用LED之间的一个轻微差异是当您在网格中的按钮时,您还需要将二极管连接到每个按钮 -1N4148是好的)。如果您对使用按钮和led网格感兴趣,您可能会想要查看这个背光按钮垫PCB.从Sparkfun。


我发现控制LEd矩阵最简单的方法是用MAX7219每个芯片可以控制多达64个led,而且只需要3个Arduino的数字输出管脚,不过价格有点贵,每个大约11美元。有很多关于使用芯片的信息Arduino网站.MAX7219不会让你单独调整led的亮度,它只会控制它们的开/关状态。如果你需要控制许多led的亮度,你可以查看TLC5940(Arduino库在这里),尽管我承认,这是棘手的多路复用芯片,因为某些时间考虑-这将是一个有点先进的项目-但每个芯片轻松控制16个led,你可以daisychain他们一起控制更多。

123 d电路比赛

参加了
123 d电路比赛

1个人制作了这个项目!

建议

  • 探索科学挑战

    探索科学挑战
  • 家具比赛

    家具比赛
  • Arduino比赛

    Arduino比赛

19评论

0
金正日Erso

4年前

你好!伟大的教程!我只会问,我需要放晶体管来降低电流吗?我已经看到其他的不可思议使用2N3904晶体管。谢谢您的回复:)

感谢伟大的信息!问题...现在我将如何整合交换机成?

0
ibenkos

6年前

聪明的想法!谢谢shearig:)

0
shekhov

6年前步骤4

在你的例子中,你将电阻连接到地面。据我所知,595发送5V到led(根据字节移动),所以你不应该用电阻保护led,短腿连接到地面吗?

0
amandaghassaei

6年前的回复步骤4

led和电阻串联的顺序并不重要。595>电阻>led>接地也很好。

0
shekhov

6年前的回复步骤4

哦..爽!感谢您的好介绍给Arduino的!这是真正的帮助

0
nheck.

7年前介绍

我喜欢你的教程!保持下去:)

0
schel

7年前介绍

最真棒!干得好!阿曼达我有一个有点相关的问题,也许你或你能不能告诉我的“IBLE或信息。我有2个DIY UNOs..I想要一个将信号发送到对方进行各种伺服系统等一个Tx和Rx能力在它们之间将是巨大的。都需要在那里做自己的事,直到UNO1告诉UNO2做别的事情....有意义吗?任何帮助超级感谢!在造说明很多帮助我更接近的解决方案!非常感谢!

0
amandaghassaei

7年前的回复介绍

//www.smiletrl.com/id/i2c-between-arduinos/

0
maewert

7年前介绍

米利斯的侧翻()是一种制造执行了很长一段时间的方案时要考虑的一个问题。请问您的代码正确地管理这个?我还没有找到一个很好的书面记录证明它是如何最好的管理。在您的代码:

'if (currentMillis - timeOfLastLedEvent > intervalON){'

我可能会认为,一旦发生滚动,您的程序就会看起来停止工作,因为左边要比右边大(如果有的话)需要49天。

可以很容易地检测到何时发生翻转(currentMillis

int delta_Time(long unsigned int timeOfLastEvent)

long unsigned int currentMillis = millis();

如果(currentMillis > = timeOfLastEvent)

返回currentMillis-timeOfLastEvent;

其他的

返回currentMillis +(4294967295-timeOfLastEvent);

我还没有尝试过,但认为有人应该记录它为群众;-)

不错的教程!

最好的祝福。

0
SuperTech-IT

7年前的回复介绍

我负责《吸血鬼杀手》项目的50天展期。

你可以随意修改我的代码。

0
maewert

7年前的回复介绍

作为超级技巧指出:简单的方法来处理翻转的方法是将减法施放,数学都有所做的:

If ((unsigned long)(current_time - previous_time) >= time_interval)

previous_time =当前时间;

//时间间隔被超过

谢谢!

0
SuperTech-IT

7年前的回复介绍

看起来很像我的代码....,哈哈!谢谢你含蓄的称赞!哈哈因为吸血鬼杀手的目的是作为一个“总”装置,并使用2秒和1分钟计时器不能设置为延迟,米尔斯()必须利用和50天展期必须得到解决,否则它会搞砸每50天左右,8电源插座是时间,如果不是这样编码的话,这可能是一场灾难。

0
amandaghassaei

7年前的回复介绍

我觉得这个函数不错,有机会我会在文章中提到它。谢谢!

0
querry43

7年前的回复介绍

看出复杂且显式键入maxint而不是使用maxint可以让您陷入困境。我想你可能想要这个:

无符号长waitUntilMillis;

void setup() {waitUntilMillis = millis() + someInterval;}

void loop(){if(millis() - waituntilmillis> = 0){时间为Up,set waituntilmillis}}

0
lapsmith

7年前介绍

哇,这是真棒!此添加书签以供将来参考,谢谢!

0
lemaxnut

7年前步骤9

我昨天刚刚得到了我的Arduino Leonardo,正在寻找一些练习代码的项目,因此这种指示的时间非常完美 - 谢谢。你是一位非常好的老师!

0
neo3587

7年前介绍

您还可以使用内部计时器来代替delay()和millis(),精度几乎是完美的,永远不会滚动。

例子:

Void setup () {

//在这里放置pinMode(), Serial.begin()等。

cli ();

TCCR1A = 0;

TTCR1B = 0;

tcnt1 = 0;

OCR1A = 0 x3e80;

TCCR1B += (1<

TIMSK1 + = (1 < < OCIE1A);//将"+"替换为OR函数

sei ();

ISR (TIMER1_COMPA_vect) {

//将代码放在这里,这段代码将每1毫秒重复一次