11.多个控制器示例
Using Multiple Controllers 使用多个控制器
One question that we often get is how to use multiple output strips at once with the library. There’s a variety of reasons why someone might want to have multiple strips coming off of their arduino (or other controller):
我们经常遇到的一个问题是,如何同时使用库输出多个灯带。有人可能会出于各种原因希望从 arduino(或其他控制器)上输出多个条带:
- Flexibility - perhaps you have an led design where strips are fanning out like the arms of a starfish, your wiring would be much simpler if you could have one controller in the middle driving all the LEDs
灵活性 - 也许您有一个 LED 设计,其中条带像海星的手臂一样呈扇形展开,如果您可以在中间有一个控制器驱动所有 LED,您的接线会简单得多 - Variety - what if you have 4 strips, all with different types of LED chipsets on them that you want to use together for a project?
多样性 - 如果您有 4 条灯带,所有灯带上都有不同类型的 LED 芯片组,您想一起用于一个项目,该怎么办? - Performance - (NOT YET, but coming) - if you could write out 8 strips in parallel, as fast as it would take you to write 1 strip, it stands to reason that you’d be able to drive 8 times as many leds before, or, conversely, run your current leds 8 times faster!
性能 - (还没有,但即将到来) - 如果你能并行写出 8 条,就像写 1 条一样快,那么你就可以驱动 8 倍的 LED 之前,或者相反,运行你当前的 LED 的速度要快 8 倍!
One of the things to think about is how you’d like to arrange your led data:
要考虑的一件事是您希望如何安排您的 LED 数据:
- Same led data going to all your strips - so when you write to the first led in your led data, the first led on all your strips has that color, and so on down the line. Good for setups where you want strips mirroring each other.
相同的 LED 数据会发送到您的所有灯条 - 因此,当您写入 LED 数据中的第一个 LED 时,所有灯带上的第一个 LED 都具有该颜色,依此类推。适用于希望条带相互镜像的设置。 - Separate sets of led data going to your strips - you set up separate arrays of CRGB data, one for each led strip.
将一组独立的 LED 数据传送到灯条 - 为每个 LED 灯条设置一个独立的 CRGB 数据阵列。 - An array of led arrays - a sort of in between option that gives you one data structure still, but also somewhat separated data as well.
一个由多个数组组成的数组–这是一种介于两者之间的选择,它既提供了一种数据结构,也提供了一些分离的数据。 - Offsetting into one giant led array - you set up one CRGB array for all of your leds, then each strip points to a different segment of that giant array.
偏移成一个巨大的 LED 阵列 - 为所有 LED 设置一个 CRGB 阵列,然后每个条带指向该巨型阵列的不同部分。
We’ll talk about these more below, note there will be examples in the library as well that will be referenced that you can use for following along or as a starting point. Note that all the examples will use the NEOPIXEL led type (as that appears to be fairly common these days, anyway).
我们将在下面详细讨论这些内容,请注意,库中也会有示例,您可以引用这些示例来学习或作为起点。请注意,所有示例都将使用 NEOPIXEL LED 类型(无论如何,这在当今似乎相当普遍)。
Mirroring strips 镜像条
Mirroring strips is prettty straight forward. All you do is tell FastLED what strips you have, and on what pins. An example of this is shown in the library’s Examples folder, under Multiple/MirroringSample. In this sample, we have 4 strips of NeoPixel leds, on pins 4, 5, 6 and 7. Each strip has 60 leds on it.
镜像条非常简单。您只需告诉 FastLED 有哪些条带,在哪些引脚上。在库的 Examples 文件夹中,Multiple/MirroringSample 下有一个例子。在这个示例中,我们有 4 条 NeoPixel 灯带,分别位于 4、5、6 和 7 引脚上。每个灯条上有 60 个 LED 灯。
The first thing that we’ll do in our code is set up our led data:
我们在代码中要做的第一件事是设置我们的 led 数据:
#include "FastLED.h"
#define NUM_LEDS_PER_STRIP 60
CRGB leds[NUM_LEDS_PER_STRIP];
This is going to be the array of our led data.
这将是我们的 LED 数据数组。
Next, we need to actually tell FastLED what led strips we have, and on what pins:
接下来,我们需要实际告诉 FastLED 我们有什么 LED 灯条,以及在哪些引脚上:
void setup() {
FastLED.addLeds<NEOPIXEL, 4>(leds, NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, 5>(leds, NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, 6>(leds, NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, 7>(leds, NUM_LEDS_PER_STRIP);
}
Each call to FastLED.addLeds tells the library about your leds. In the code above, we’re telling the library “There’s four neopixel strips, on pins 4, 5, 6, and 7. Each strip is using our led array leds, and has NUM_LEDS_PER_STRIP (which we’ve defined to be 60).”
每次调用 FastLED.addLeds 都会告诉程序库有关 LED 的信息。在上面的代码中,我们告诉库 “有四个 neopixel 灯条,分别位于 4、5、6 和 7 号引脚上。每个条带都使用了我们的 led 阵列 leds,并且有 NUM_LEDS_PER_STRIP(我们定义为 60)”。
Now, there’s nothing special to do in the rest of your code. If you want a simple moving dot, you can just do:
现在,在代码的其余部分没有什么特别的事情要做。如果你想要一个简单的移动点,你可以做:
void loop() {
for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
leds[i] = CRGB::Red; // set our current dot to red
FastLED.show();
leds[i] = CRGB::Black; // set our current dot to black before we continue
}
}
Now, when this code is run, each strip will have a dot moving back and forth along it, all four in perfect sync/harmony with each other!
现在,当运行此代码时,每个条带都会有一个点沿着它来回移动,所有四个点彼此完美同步/和谐!
Multiple led arrays 多个 LED 阵列
Of course, sometimes you may want your different strips to do different things. For this example, there’s say there’s three led strips, on pins 10, 11 and 12. You want a moving dot again, but this time, you want the first strip to have a red dot, the second strip to have a green dot, and the third strip to have a blue dot. This time, instead of one CRGB array named leds, we’re going to make three, helpfully named for what we’re doing (this example is in Examples, under Multiple/MultiArrays):
当然,有时您可能希望不同的灯条做不同的事情。在这个例子中,假设有三个 LED 灯条,分别位于 10、11 和 12 号引脚上。您又想要一个移动的点,但这次,您希望第一个灯条有一个红点,第二个灯条有一个绿点,第三个灯条有一个蓝点。这一次,我们不再使用一个名为 leds 的 CRGB 数组,而是使用三个,并根据我们要做的事情命名(此示例位于 "示例 "中的 "Multiple/MultiArrays
"下):
#include "FastLED.h"
#define NUM_LEDS_PER_STRIP 60
CRGB redLeds[NUM_LEDS_PER_STRIP];
CRGB greenLeds[NUM_LEDS_PER_STRIP];
CRGB blueLeds[NUM_LEDS_PER_STRIP];
Our setup function looks a little bit like the one above did, however this time we’re pointing each strip at a different led array:
我们的设置功能看起来有点像上面的设置功能,但是这次我们将每个灯带指向不同的 LED 阵列:
void setup() {
FastLED.addLeds<NEOPIXEL, 10>(redLeds, NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, 11>(greenLeds, NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, 12>(blueLeds, NUM_LEDS_PER_STRIP);
}
Now, this time, since we have three sets of led data, in our loop function we’re going to need to write what we want into each array separately:
现在,这一次,由于我们有三组 led 数据,在我们的循环函数中,我们需要将我们想要的内容分别写入每个数组:
void loop() {
for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
// set our current dot to red, green, and blue
redLeds[i] = CRGB::Red;
greenLeds[i] = CRGB::Green;
blueLeds[i] = CRGB::Blue;
FastLED.show();
// clear our current dot before we move on
redLeds[i] = CRGB::Black;
greenLeds[i] = CRGB::Black;
blueLeds[i] = CRGB::Black;
delay(100);
}
}
Notice how, this time, in our loop, we have to write data into each of the three led arrays, since we want different things showing on each led strip. Now, what if you wanted to programatically choose which led strip you were writing a color value to? Well, that brings us to our next example, the array of led arrays.
请注意,这次在循环中,我们必须将数据分别写入三个 LED 阵列,因为我们希望每个 LED 灯条显示不同的内容。现在,如果你想通过编程选择向哪个 led 条写入颜色值,会怎样呢?这就是我们的下一个例子,led 阵列数组。
Array of led arrays led阵列
Now let’s get a little fancier. In order to make a dot that moves from one led strip to the next using the example above, you’d have to have some really ugly code to “pick” the current strip you were writing to. Or a lot of duplicated code. That’s never any fun. Instead, here’s a technique for using an array of arrays. Where before you had individual CRGB arrays of leds, now you have an array of CRGB arrays of leds (this example is in Examples, under Multiple/ArrayOfLedArrays):
现在,让我们变得更复杂一些。要想用上面的例子制作一个能从一个发光条移动到下一个发光条的点,你必须编写一些非常难看的代码来 "选择 "你要写入的当前发光条。或者是大量重复的代码。这可一点都不好玩。相反,这里有一种使用数组的技术。以前是单个 CRGB 灯具数组,现在是 CRGB 灯具数组的数组(此示例位于示例中的 Multiple/ArrayOfLedArrays 下):
#include "FastLED.h"
#define NUM_STRIPS 3
#define NUM_LEDS_PER_STRIP 60
CRGB leds[NUM_STRIPS][NUM_LEDS_PER_STRIP];
This has set up a two dimensional array. If you want to access the first led on the first strip, you would use leds[0][0]
. If you wanted to access the third led on the second strip, you would use leds[1][2]
and so. Setup looks mostly the same, except now we have to tell it which array to use for each strip:
这已经建立了一个二维数组。如果要访问第一个灯条上的第一个 LED,则使用 leds[0][0]
.如果您想访问第二个条带上的第三个 LED,您将使用 leds[1][2]
等等。设置看起来基本相同,只是现在我们必须告诉它每个条带使用哪个数组:
void setup() {
FastLED.addLeds<NEOPIXEL, 10>(leds[0], NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, 11>(leds[1], NUM_LEDS_PER_STRIP);
FastLED.addLeds<NEOPIXEL, 12>(leds[2], NUM_LEDS_PER_STRIP);
}
Now, in the loop, instead of just looping over the leds, we can also loop over the strips. This code will generate a dot that moves down the first strip, then the second strip, and finally the third strip:
现在,在环路中,我们不仅可以在 LED 上循环,还可以在条带上循环。此代码将生成一个点,该点向下移动第一个条带,然后是第二个条带,最后是第三个条带:
现在,在循环中,我们可以在条带上循环,而不仅仅是在 LED 上循环。这段代码将生成一个点,沿着第一条向下移动,然后是第二条,最后是第三条:
void loop() {
// This outer loop will go over each strip, one at a time
for(int x = 0; x < NUM_STRIPS; x++) {
// This inner loop will go over each led in the current strip, one at a time
for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
leds[x][i] = CRGB::Red;
FastLED.show();
leds[x][i] = CRGB::Black;
delay(100);
}
}
}
One array, many strips 一个阵列,多个条带
Maybe you don’t want an array of arrays. Maybe you have patterns that just want one single array with all the leds, and let the library figure out where in that array the data for each strip is. Once again, we setup our led data (this example is in Multiple/MuiltipleStripsInOneArray):
也许你不需要一个数组的数组。也许您的图案只需要一个包含所有 LED 的数组,然后让库找出每个灯条的数据在数组中的位置。再次,我们设置led 数据(本例在 Multiple/MuiltipleStripsInOneArray
中):
#include "FastLED.h"
#define NUM_STRIPS 3
#define NUM_LEDS_PER_STRIP 60
#define NUM_LEDS NUM_LEDS_PER_STRIP * NUM_STRIPS
CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];
Notice this time, we still have only one led array, but this time it is large enough to contain information on all the leds in all the strips (180 leds in total). We’ll also be using a slightly modified version of the addLeds method. This method takes 3 arguments, the led array, an offset into that array (think of this as where the strip being added starts in the array), and how many leds there are. So, in the example below, the strip on pin 10 starts at offset 0 and has 60 leds, the strip on pin 11 starts at offset 60 and also has 60 leds, and finally, the strip on pin 12 starts at offset 120 and also has 60 leds.
请注意,这次我们仍然只有一个 LED 阵列,但它已经足够大,足以包含所有灯条(共 180 个 LED)中所有 LED 的信息。我们还将使用稍作修改的 addLeds
方法。该方法需要 3 个参数:led 数组、该数组的偏移量(可将其视为添加的灯条在数组中的起始位置)以及灯条的数量。因此,在下面的示例中,引脚 10 上的条带从偏移量 0 开始,有 60 个 LED 灯;引脚 11 上的条带从偏移量 60 开始,也有 60 个 LED 灯;最后,引脚 12 上的条带从偏移量 120 开始,也有 60 个 LED 灯。
void setup() {
// tell FastLED there's 60 NEOPIXEL leds on pin 10, starting at index 0 in the led array
FastLED.addLeds<NEOPIXEL, 10>(leds, 0, NUM_LEDS_PER_STRIP);
// tell FastLED there's 60 NEOPIXEL leds on pin 11, starting at index 60 in the led array
FastLED.addLeds<NEOPIXEL, 11>(leds, NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
// tell FastLED there's 60 NEOPIXEL leds on pin 12, starting at index 120 in the led array
FastLED.addLeds<NEOPIXEL, 12>(leds, 2 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
}
Now, take a look at the loop method. We’re still moving a dot down each strip, one strip at a time - but there’s only one loop, going over all the leds:
现在,看一下循环方法。我们仍然在每个条带上移动一个点,一次一个条带 - 但只有一个循环,遍历所有 LED:
void loop() {
for(int i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB::Red;
FastLED.show();
leds[i] = CRGB::Black;
delay(100);
}
}
Managing your own output 管理自己的输出
FastLED helpfully writes to all the leds strips every time you call show. However, sometimes, that might not be what you want. For example, you may want to split leds over multiple lines to conserve memory. In this case, you can sidestep fastled’s automatic display (at the cost of easy global brightness management). Here’s a quick example:
每次调用显示时,FastLED 都会写入所有 LED 灯条。但有时,这可能不是您想要的。例如,为了节省内存,您可能希望将 leds 分割成多行。在这种情况下,你可以避开 fastled
的自动显示(代价是全局亮度管理变得简单)。下面是一个快速示例:
#include "FastLED.h"
#define NUM_LEDS 80
#define NUM_STRIPS 4
CRGB leds[NUM_LEDS];
CLEDController *controllers[NUM_STRIPS];
uint8_t gBrightness = 128;
void setup() {
controllers[0] = &FastLED.addLeds<WS2812,1>(leds, NUM_LEDS);
controllers[1] = &FastLED.addLeds<WS2812,2>(leds, NUM_LEDS);
controllers[2] = &FastLED.addLeds<WS2812,10>(leds, NUM_LEDS);
controllers[3] = &FastLED.addLeds<WS2812,11>(leds, NUM_LEDS);
}
void loop() {
// draw led data for the first strand into leds
fill_solid(leds, NUM_LEDS, CRGB::Red);
controllers[0]->showLeds(gBrightness);
// draw led data for the second strand into leds
fill_solid(leds, NUM_LEDS, CRGB::Green);
controllers[1]->showLeds(gBrightness);
// draw led data for the third strand into leds
fill_solid(leds, NUM_LEDS, CRGB::Blue);
controllers[2]->showLeds(gBrightness);
// draw led data for the first strand into leds
fill_solid(leds, NUM_LEDS, CRGB::White);
controllers[3]->showLeds(gBrightness);
}
Now you can write led data one strip/pin at a time.
现在,您可以一次写入一个灯条/引脚的 LED 数据。
Or, alternatively (using some new pieces added recently to the FastLED object):
或者,另一种方法(使用最近添加到 FastLED 对象中的一些新部件)::
#include "FastLED.h"
#define NUM_LEDS 80
#define NUM_STRIPS 4
CRGB leds[NUM_LEDS];
uint8_t gBrightness = 128;
void setup() {
FastLED.addLeds<WS2812,1>(leds, NUM_LEDS);
FastLED.addLeds<WS2812,2>(leds, NUM_LEDS);
FastLED.addLeds<WS2812,10>(leds, NUM_LEDS);
FastLED.addLeds<WS2812,11>(leds, NUM_LEDS);
}
void loop() {
// draw led data for the first strand into leds
fill_solid(leds, NUM_LEDS, CRGB::Red);
FastLED[0].showLeds(gBrightness);
// draw led data for the second strand into leds
fill_solid(leds, NUM_LEDS, CRGB::Green);
FastLED[2].showLeds(gBrightness);
// draw led data for the third strand into leds
fill_solid(leds, NUM_LEDS, CRGB::Blue);
FastLED[3].showLeds(gBrightness);
// draw led data for the first strand into leds
fill_solid(leds, NUM_LEDS, CRGB::White);
FastLED[4].showLeds(gBrightness);
}