有没有办法在arduino上具有超过14个输出引脚?


52

我可以在Arduino上使用14个以上的输出引脚吗?我正在一个项目中,我需要单独点亮几个LED。我只有一个Arduino Uno,我不想买一个Mega。


本着可扩展性的精神,I2C甚至可以作为Arduino的选项吗?
克里斯·奥

@ChrisO I2C是什么意思?因为据我了解,移位寄存器将被视为I2C。
JVarhol 2014年

哦,然后让我回答我的问题;-)这是有关此总线标准的维基百科文章。而且我刚刚从Wire lib找到对I2C的支持,因此您可以将I2C链连接到您的Uno。
克里斯·奥

@JVarhol不完全是。I2C(也称为TWI)是2线接口,而SPI可以视为3线接口。
Klaus-Dieter Warzecha 2014年

1
@JVarhol您是否已经为您的项目选择了解决方案?如果是,则编辑您的问题并接受与您的解决方案相匹配(或最接近)的答案将非常有用。
jfpoilpret 2014年

Answers:


50

扩展Arduino上可用输出引脚集的一种常见方法是使用移位寄存器,例如74HC595 IC(链接到数据表)。

您需要3个引脚来控制这些芯片:

  1. 时钟
  2. 锁存器
  3. 数据

在程序中,您可以使用shiftOut()命令一次将数据一次传递给移位寄存器,如下所示:

shiftOut(dataPin, clockPin, data); 

使用该命令,可以使用data变量中的8位设置595 IC上的8个输出中的每个输出。

使用一个595,您将获得5个引脚(IC上有8个引脚,但要花费3个与之对话)。要获得更多输出,您可以通过将595的串行输出引脚连接到下一个595的数据引脚,以菊花链的方式将它们串联在一起。您还必须将所有595 IC的时钟和锁存引脚连接在一起。

生成的电路(使用一个595)如下所示:

使用595移位寄存器的电路

上图取自此codeproject.com网页:

锁存引脚用于在将数据移出时使595输出保持稳定,如下所示:

digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, data); 
digitalWrite(latchPin, HIGH);

1
Thx,忘了包含移位寄存器的工作原理。我本来打算,但是我不得不离开我的电脑,当我回来时,它让我无所适从。:)
JVarhol 2014年

没问题,这就是为什么我们是一个社区。我们补充彼此的答案。但是也很高兴您在答案中也添加了一些很好的提示,特别是关于EZ-Expander防护罩的提示。它使那些无法轻松制作PCB的人能够扩展可用端口的数量。
里卡多

2
同样,它也使编程变得容易,您不必移入数据并为时钟脉冲,然后激活锁存器。我已经了解屏蔽一段时间了,我认为它非常适合初学者。最好的事情是,因为该代码是开源的,所以即使您没有使用实际的防护板而是拥有自己的板子或使用面包板,也可以使用该代码。
JVarhol 2014年

1
不要忘记,您可以无限期地(理论上)将它们链接在一起,因此2个8位寄存器可以变成1个16位。
Scott M.

谢谢!这是一个很棒的代码项目描述的存档链接,以防万一该链接断开了archive.fo/1uvPE
akhmed 2016年

27

您可以通过两种方式从arduino中获取更多的引脚。

第一种方法是将模拟引脚用作数字输出引脚,这确实很容易做到。您需要做的只是将A0-A5用作引脚14,15,16,17,18,19。例如,要向引脚A0写入高电平,只需使用digitalWrite(14,HIGH)。

从Arduino获得更多引脚的另一种方法是使用移位寄存器。为此,我建议使用EZ-Expander Shield,它允许您在导入EZ-Expander库时使用digitalWrite([20-35],HIGH)。但是,该屏蔽仅允许将引脚用作输出,并使用引脚8,12和13来控制移位寄存器。

很棒的是,您可以同时使用上述两种方法,而不会出现任何问题。


3
根据Arduino参考,您实际上可以直接使用A0- A5标识符,而不是使用数字14-19。例如,digitalWrite(A0, HIGH)
彼得·布鲁姆菲尔德

3
@ PeterR.Bloomfield两者都是正确的,但是我建议A0-A5是为了简化和易于阅读。LED闪烁不是什么大问题,但是当您进行大型项目时,很少会养成习惯。
匿名企鹅

2
实际上,尽管两者都可以在UNO和兼容板上完成工作,但比前者总是映射到正确的物理(模拟)引脚digitalWrite(A0)要正确得多digitalWrite(14)。在另一块板上,pin 14实际上可能不是A0,例如pin 14在MEGA上为Serial3,TX并且不会影响您要使用的模拟引脚。即,如果digitalWrite在模拟引脚上使用,请使用A0- A5参考。
Madivad

18

如果要驱动LED,那么还可以使用MAX7219,它可以驱动64个LED,而无需额外的电路(不需要晶体管来放大信号)。

驱动MAX7219在Arduino上仅需要3个输出引脚。另外,您可以找到一些Arduino库

如果需要为64个以上的LED供电,则还可以将其中的几个链接起来。

我已成功将其用于多个7段LED显示器。

缺点:价格昂贵(约10美元)。


我确实忘记了MAX7219,感谢您的发帖!
JVarhol 2014年

384个LED ...哇!加上两个用于USB推论的引脚。想知道您可以创建哪种烦人的小装饰品(有足够的电源)。
匿名企鹅2014年

17

您可以使用Charlieplexing。使用这种技术,您可以直接n*(n-1)从n个引脚驱动LED。因此,使用3针可以驱动6个LED,4针-12个LED,5针-20个LED等。

范例:

3个引脚上的六个LED

PINS        LEDS
0 1 2   1 2 3 4 5 6
0 0 0   0 0 0 0 0 0
0 1 Z   1 0 0 0 0 0
1 0 Z   0 1 0 0 0 0
Z 0 1   0 0 1 0 0 0
Z 1 0   0 0 0 1 0 0
0 Z 1   0 0 0 0 1 0
1 Z 0   0 0 0 0 0 1
0 0 1   0 0 1 0 1 0
0 1 0   1 0 0 1 0 0
0 1 1   1 0 0 0 1 0
1 0 0   0 1 0 0 0 1
1 0 1   0 1 1 0 0 0
1 1 0   0 0 0 1 0 1
1 1 1   0 0 0 0 0 0

在此处输入图片说明

您可以在这里看到更好的教程。


需要注意的一件事是,该技术使您可以控制更多的led,但不必同时控制。
kontur

1
@kontur是的,你是对的。但是就持久性而言,您可以认为它们是。问题没有这样的细节。
丹尼尔·格里洛

不使用移位寄存器,Charlieplexing并不是唯一的LED复用方法。
linhartr22'9

1
@ linhartr22我从来没有说过这是唯一的方法。Charlieplexing只是解决此问题的常用方法。我的答案是第七。因此,其他可能性已经显示出来。
Daniel Grillo

@DanielGrillo我本来应该更具体一点,并解释一下如何在没有移位寄存器且不受Charlieplexing限制的情况下完成通常用于LED立方体的列和行复用。4x4行列矩阵可以通过8条I / O线分别控制16个led。一个4x4x4立方体可以通过12条I / O线单独控制64个led(甚至在Uno上也可以使用模拟A0-A5作为数字线)。
linhartr22'9

13

I 2 C(线)

您可以使用I 2 C协议(Wire库)连接到其他设备,例如端口扩展器。例如,MCP23017。

我用其中一种芯片连接到LCD板上。MCP23017具有16个端口,可以配置为输入或输出。如果需要,它们可以作为中断输入。

将这16个中的13个连接到LCD的示例:

MCP23017连接到LCD屏幕

现在,我们仅使用两根电线(SDA / SCL)加上电源和地线即可连接到Arduino:

MCP23017连接到Arduino


一些第三方制造商制造的板上带有4个MCP23017,这为您提供了64个输入/输出:

board板


多路复用器

您可以使用诸如74HC4051(8个端口)或74HC4067(16个端口)之类的模拟多路复用器将一个引脚连接到8/16端口之一(但在给定时间只能连接一个),如下所示:

74HC4051多路复用器

它们是双向的,因此可以用作输入或输出扩展器。


带74HC595的SPI

使用SPI可以将快速串行数据发送到移位寄存器,例如74HC595。这些可以菊花链在一起。在此示例中,我仅用3个I / O引脚(MOSI / MISO / SCK)加上电源和地来控制32个LED。

74HC595驱动32个LED


我在一个商业LED标识中发现72个LED由74HC595芯片驱动。

滚动LED标志

它具有9个芯片来驱动列(9 x 8 = 72个LED)和一个芯片来驱动行,采用多路复用配置。


具有MAX7219的SPI

如果您只想驱动LED,通常可以多路复用它们。MAX7219设计用于驱动LED矩阵,例如7段显示器,从而简化了这一过程:

MAX7219,具有7段显示

或64个LED矩阵:

MAX7219,带有64个LED矩阵

在这两种情况下,都可以通过菊花链方式链接在一起,例如:

MAX7219菊花链

所有这些示例仅使用Arduino的3个引脚(MOSI / MISO / SCK)加上电源和地。


具有MCP23S17的SPI

前面提到的16端口端口扩展器(MCP23017)也带有SPI变体(MCP23S17),其功能几乎相同。它使用多一根电线,但是会更快。


其他协议

LED灯条(如NeoPixel的灯条)有自己的协议。Josh Levine在Youtube上发布了一篇帖子,作者使用Duemilanove驾驶了1000多个像素!


参考文献


12

移位寄存器已在其他答案中提到,它们绝对是许多项目的绝佳选择。它们便宜,简单,速度适中,通常可以链接在一起以增加更多输出。但是,它们有一个缺点,它们通常需要排他地使用几个引脚(2到4之间,具体取决于您如何设置它们)。

另一种选择是使用更高级的端口扩展器,例如16位MCP23017和MCP23S17。它们分别支持I2C和SPI,这意味着您可以将它们与其他几个设备(可能是不同类型)放置在总线上。总线上的每个设备都可以单独寻址,这意味着您只需要2或3个引脚即可与所有这些设备进行通信。更新速度通常非常快,因此您不太可能在Arduino项目中遇到显着的延迟(即传输延迟)。

在低水平上,使用I2C或SPI比简单的移位寄存器要复杂得多。但是,有Arduino的库代码可以帮助您解决这一问题。例如,请参见以下问题:如何在Arduino上使用I2C设备?


哇,我从来不知道这些,不好,看着他们!
JVarhol 2014年

可以使用I2C控制LED吗?
Pro Q

1
@ProQ您不能直接使用I2C控制标准LED。但是,有可能获得一些具有内置I2C驱动器的LED产品。这通常适用于带有许多LED的产品,例如条状或矩阵状。
彼得·布鲁姆菲尔德

8

除了里卡多的答案外,维基百科在移位寄存器上指出的是:

移位寄存器最常见的用途之一是在串行和并行接口之间进行转换。当需要更多的通用输入/输出引脚时,SIPO寄存器通常连接到微处理器的输出。这允许仅使用两个或三个引脚来控制多个二进制设备,但比并行I / O慢。

在链接的文章里卡多中,您可以看到移位寄存器的图。

移位寄存器图

这里发生的是,您将8个引脚的数据按顺序放置,并且对于每个时钟周期,移位寄存器将移位(将二进制数据从每个锁存器移至下一个锁存器),直到其“绕圈”,即第一位到达最后一针。移位寄存器还有一个输入,您可以在其中打开/关闭移位,以便在将数据移位到该位置后可以保持状态。有关简单的演示,请参见以下动画。

移位寄存器动画

在这里,红灯是串行输入,而绿灯则表示此简化的SIPO移位寄存器中的锁存器状态。数据移到位置后,可以关闭移位,然后可以读取引脚。在这个例子中我移出了10101011

从这些示例中,您可以意识到串行传输比并行传输要慢,因为您必须等待移位寄存器将这些位移位到它们的位置。您将不得不等待与要加载的位相同数量的时钟滴答。这是您不能无限期地链接它们的众多原因之一,因为加载将花费很长时间。


1
+1获取更多信息,并获得漂亮的动画GIF及其效果。您在哪里找到了GIF?还是你做到了?
里卡多

1
@Ricardo我用Digital Works创建了电路,然后打印屏幕,编辑gif动画器。
totymedli 2014年

6

正如您已经写过的,您可以将所有引脚(包括TX和RX)用作数字输出。我前一阵子做了一个演示,并录制了这个相当荒谬的项目的视频-20个20个LED的针脚

如由彼得R.布龙菲尔德 在这里,你必须断开TX和RX上传。此外,您没有足够的引脚来读取传感器的可能的交互性,并且必须确保未达到总电流限制。不要忘记,如果直接用Arduino驱动它们,则限于5V led。

因此,强烈建议使用里卡多描述的通用移位寄存器和595 。

  • 他们便宜!
  • 级联它们相当容易。
  • 当您使用硬件SPI时,可以获得很大的速度。

不久前,当我意识到更新引擎艺术家Dominik JaisKawaii我的焊接和编程部分(链接的文本为德语)时,我就使用了它们。

在这里,只有一堆595用于驱动8x11 led的显示。由于LED灯是从12V SMD LED 灯带上切下的,因此需要一个额外的电源和一些连接到移位寄存器输出引脚上的UDN2803A Darlington阵列。

其他通用方法包括使用PCF8574(A)8位端口扩展器,该扩展器通过I2C总线进行控制。

无论如何,我会先尝试一下595移位寄存器。

但是,如果需要控制几个RGB LED,则可能需要寻找更专业的解决方案。某些RGB led 带有自己的WS2812。这些细小片段可以级联(1-Wire总线),并通过它们在链中的位置进行寻址。


3

如果全部涉及LED,那么WS2812B LED灯带又或者驱动芯片本身呢?您仅需一根针即可控制几乎无限数量的LED!

尽管人们习惯于条状显示,但它们可以作为独立的LED使用(在Adafruit上称为neo像素)。或者,如果您仅驱动单色,则每个WS2811芯片可以通过将每个RGB输出用于单个LED来控制3个LED。

我最近刚创建了一个使用5个此类LED的项目:Door1打开/关闭,Door2打开/关闭,motor1激活,motor2激活和电源。“活动” LED是双重用途的,因为我有红色是来自活动电动机的输入,绿色是Arduino内部的活动标志。

只需安装1针和库即可,您可以控制任意数量的LED


2

我自己没有使用此方法,但是我在网页MUX-DEMUX:CD4051 Parlor Tricks上找到了这个巧妙的技巧

无论您选择使用哪种方法来驱动输出或读取输入(移位寄存器,多路复用器或直接使用Arduino引脚本身),都可以通过巧妙地使用并行电路对来形成双倍的输出或输入数量(以形成双路)。输入或输出 ),在每个并行分支上采用相反方向的二极管,并将输入/输出切换为高电平和低电平。

为了说明输出方法(在这种情况下为LED,请注意,不需要额外的二极管):

LED银行

如果您在此示例中将一对LED视为“ bank”,并且要点亮LED_0,则需要将PIN 17设置为HIGH,将PIN 18设置为LOW。(引脚号令人困惑,但它们与后面的示例匹配,所以对我来说是光秃秃的)。要点亮LED_1,只需反转PINS。LED的二极管特性可防止电流沿相反方向流动,从而使另一方向保持关闭状态。

为了说明输入方法(在这种情况下为CdS,请注意,需要额外的二极管):

CDS银行

如果要在CdS光传感器上进行模拟读取,这会变得更加复杂。首先,您需要在每个传感器上增加一个二极管来控制流量。其次,由于您正在读取值,因此需要将输入拉高或拉低以防止其浮动。作为一个懒惰的人,我将使用内部上拉电阻将其拉高。要读取CdS_0,请将PIN 17模式设置为OUTPUT并将其设置为LOW。这使其成为地面。然后,将PIN 18模式设置为INPUT并将其设置为HIGH来接合上拉电阻。现在,您可以设置对PIN 18(也称为模拟引脚4)进行读取。要访问另一个传感器,只需切换模式和输出。

因此,如果您有一个CD4051 8端口多路复用器,使用Arduino上的5个引脚(而不是通常的3个),则可以获得16个输入或输出,或两者的混合。

使用CD4051进行16个输出/输入

同样,如果您具有4067 16端口多路复用器,则可以获得32个输入或输出,或两者的混合。

一个示例草图是:

/*
 * Example of getting 16 i/o from 5 pins using a CD4051
 *
 * Based on tutorial and code by david c. and tomek n.* for k3 / malmö högskola
 * http://www.arduino.cc/playground/Learning/4051?action=sourceblock&ref=1
 */ 


int selPin[] = { 14, 15, 16 }; // select pins on 4051 (analog A0, A1, A2)
int commonPin[] = { 17, 18};   // common in/out pins (analog A3, A4)
int led[] = {LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW };  // stores eight LED states
int CdSVal[] = { 0, 0, 0, 0 }; // store last CdS readings
int cnt = 0;  // main loop counter
int persistDelay = 100; // LED ontime in microseconds


void setup(){
  Serial.begin(9600);  // serial comms for troubleshooting (always)
  for(int pin = 0; pin < 3; pin++){ // setup select pins
    pinMode(selPin[pin], OUTPUT);
  } 
}


void loop(){
  flashLEDs();
  if (cnt == 0){
    for(int x; x < 8; x++){
      led[x] = random(2);
    }
  }
  cnt++;
  if (cnt > 100) { cnt = 0; }
}


void flashLEDs() {
  for(int pin = 0; pin < 2; pin++) {  // set common pins low
    pinMode(commonPin[pin], OUTPUT);
    digitalWrite(commonPin[pin], LOW);
  } 
  for (int bank = 0; bank < 4; bank++) {
    for(int pin = 0; pin < 3; pin++) { // parse out select pin bits
      int signal = (bank >> pin) & 1;  // shift  & bitwise compare
      digitalWrite(selPin[pin], signal);
    }
    if (led[bank * 2]){        // first LED
      digitalWrite(commonPin[0], HIGH);  // turn common on
      delayMicroseconds(persistDelay);   // leave led lit
      digitalWrite(commonPin[0], LOW);   // turn common off
    } 
    if (led[bank * 2 + 1]){     // repeat for second LED
      digitalWrite(commonPin[1], HIGH);
      delayMicroseconds(persistDelay);
      digitalWrite(commonPin[1], LOW); 
    }
  } 
}

就像我在第一行中所说的那样,完整的解释可以在MUX-DEMUX上找到:CD4051 Parlor Tricks


1

对于一个班级项目,我使用了CD4024和两个Arduino引脚来驱动7段显示器。

这种方法有一些警告。例如,要将一个high值写入纹波计数器的第一个输出,只需要一个reset和两次切换时钟引脚即可。但是,如果要写入high所有n个引脚,则需要切换时钟引脚2 n倍,在此期间所有其他引脚都在不断切换和关闭。

如果您的应用程序可以解决这些限制,并且您的引脚短缺,那么这是另一种选择。

奖金回答:有很多的复用输入的例子在这里,其中有许多也适用于多路输出。


出于您自己指出的原因,使用7级计数器驱动7段显示器似乎不是最佳方法。
jfpoilpret 2014年

1

经过一些工作(安装其他引导加载程序),Uno上的ICSP1和JP2接头连接器上就可以使用另外七个I / O线。备用引导加载程序称为HoodLoader2。它允许您在Uno的Atmega328和Atmega16U2上安装草图。使用此方法将使处理多个处理器成为主要困难。

在Uno上,ICSP1和JP2接头连接到Atmega16U2的引脚PB1 ... PB7。此外,Atmega16U2具有大约9个I / O引脚,与电路板没有连接。在显微镜下工作的人也许可以将电线连接到16U2上的总共18个I / O引脚上,而将其他三个I / O引脚保留在其普通连接上。

HoodLoader2也可以在Mega板上使用。


0

这里有很多不错的答案,但是如果您花费时间,就会发现购买Mega便宜。

我的3/2天价值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.