
一个完全从头开始制作的自定义矩阵制作,想要玩的小伙伴试试看吧。
首先是LED矩阵的布局,该矩阵采用 16x8 配置,并以 OXPLOW 布局布局(OXPLOW 是一种矩阵类型,其中 LED 在一行中单向移动,然后在下一行向后移动,依此类推,也就是每一排的最后一个都连到下一排的第一个,这种布局也称为 boustrophedon)。还有另一种布局是蛇形布局,LED 像蛇一样以连续的链条布局。

矩阵通过FAST LED库控制,但可以使用Adafruit的Neopixel库或SmartMatrix库等一系列现有库进行操作。
所需材料有:WS2812B 发光二极管、定制电路板、Arduino Nano、面包板。
WS2812B不陌生吧,之前达尔闻说也发过很多WS2812B的项目。WS2812B是一款智能控制LED光源,将控制电路和RGB芯片集成到5050组件封装中,内部包括智能数字端口数据锁存器和信号整形放大驱动电路。
数据传输协议使用单 NZR 通信模式。上电复位后,DIN端口接收来自控制器的数据,第一个像素收集初始24位数据然后发送到内部数据锁存器,其他通过内部信号整形放大电路重塑的数据通过DO端口发送到下一个级联像素。

WS2812B工作电压在+3.5~+5.3V DC之间。
从原理图开始设计,该原理图由 128 个 RGB LED 组成,在 OXPLOW 布局中来回连接。有一个 CON4 接插件,用于连接 VCC、GND、Din 和 Dout 引脚,也有单独的用于 VCC、GND 和 Din 的三个不同引脚连接。所有 LED 的 VCC 和 GND 都并联连接。
第 1 个的 Dout 进入第 2 个的 Din,第 2 个的 Dout 转到第 3 个像素的 Din,一直持续到第 128 个。

每个WS2812 LED都需要一个0.1uF的电容器才能正常工作,但由于空间有限,没有添加电容器。该板工作正常,但如果它有一些问题,可以添加一个带有VCC和GND的外部电容。
然后进行PCB制作与打样、器件焊接:


要驱动矩阵板,需要按照下面的接线图将Arduino Nano连接到矩阵。

矩阵的VCC将连接到Arduino的5V
接地到接地
矩阵至D9的Din(任何PWM引脚)
为了使用这个板,可以利用一堆现有的库,比如 FASTLED 库。 FASTLED是一个用于控制各种LED芯片组的库,例如adafruit(Neopixel,DotStar,LPD8806),Sparkfun(WS2801)等。 这是它的GitHub页面,需要在Arduino IDE中下载并安装库。https://github.com/FastLED/FastLED 这是将使用的主程序,被称为NoisePlusPalette,可以在FASTLED示例中找到。
#include
#define LED_PIN 9
#define BRIGHTNESS 96
#define LED_TYPE WS2811
#define COLOR_ORDER GRB
const uint8_t kMatrixWidth = 16;
const uint8_t kMatrixHeight = 8;
const bool kMatrixSerpenTIneLayout = false;
#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
#define MAX_DIMENSION ((kMatrixWidth>kMatrixHeight) ? kMatrixWidth : kMatrixHeight)
// The leds
CRGB leds[kMatrixWidth * kMatrixHeight];
staTIc uint16_t x;
staTIc uint16_t y;
staTIc uint16_t z;
uint16_t speed = 20; // speed is set dynamically once we've started up
uint16_t scale = 30; // scale is set dynamically once we've started up
uint8_t noise[MAX_DIMENSION][MAX_DIMENSION];
CRGBPalette16 currentPalette( PartyColors_p );
uint8_t colorLoop = 1;
void setup() {
delay(3000);
LEDS.addLeds<led_type,led_pin,color_order>(leds,NUM_LEDS);
LEDS.setBrightness(BRIGHTNESS);
// Initialize our coordinates to some random values
x = random16();
y = random16();
z = random16();
}
// Fill the x/y array of 8-bit noise values using the inoise8 function.
void fillnoise8() {
uint8_t dataSmoothing = 0;
if( speed < 50) {
dataSmoothing = 200 - (speed * 4);
}
for(int i = 0; i < MAX_DIMENSION; i++) {
int ioffset = scale * i;
for(int j = 0; j < MAX_DIMENSION; j++) {
int joffset = scale * j;
uint8_t data = inoise8(x + ioffset,y + joffset,z);
data = qsub8(data,16);
data = qadd8(data,scale8(data,39));
if( dataSmoothing ) {
uint8_t olddata = noise[i][j];
uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing);
data = newdata;
}
noise[i][j] = data;
}
}
z += speed;
// apply slow drift to X and Y, just for visual variation.
x += speed / 8;
y -= speed / 16;
}
void mapNoiseToLEDsUsingPalette()
{
static uint8_t ihue=0;
for(int i = 0; i < kMatrixWidth; i++) {
for(int j = 0; j < kMatrixHeight; j++) {
uint8_t index = noise[j][i];
uint8_t bri = noise[i][j];
if( colorLoop) {
index += ihue;
}
if( bri > 127 ) {
bri = 255;
} else {
bri = dim8_raw( bri * 2);
}
CRGB color = ColorFromPalette( currentPalette, index, bri);
leds[XY(i,j)] = color;
}
}
ihue+=1;
}
void loop() {
// Periodically choose a new palette, speed, and scale
ChangePaletteAndSettingsPeriodically();
fillnoise8();
mapNoiseToLEDsUsingPalette();
LEDS.show();
// delay(10);
}
#define HOLD_PALETTES_X_TIMES_AS_LONG 1
void ChangePaletteAndSettingsPeriodically()
{
uint8_t secondHand = ((millis() / 1000) / HOLD_PALETTES_X_TIMES_AS_LONG) % 60;
static uint8_t lastSecond = 99;
if( lastSecond != secondHand) {
lastSecond = secondHand;
if( secondHand == 0) { currentPalette = RainbowColors_p; speed = 20; scale = 30; colorLoop = 1; }
if( secondHand == 5) { SetupPurpleAndGreenPalette(); speed = 10; scale = 50; colorLoop = 1; }
if( secondHand == 10) { SetupBlackAndWhiteStripedPalette(); speed = 20; scale = 30; colorLoop = 1; }
if( secondHand == 15) { currentPalette = ForestColors_p; speed = 8; scale =120; colorLoop = 0; }
if( secondHand == 20) { currentPalette = CloudColors_p; speed = 4; scale = 30; colorLoop = 0; }
if( secondHand == 25) { currentPalette = LavaColors_p; speed = 8; scale = 50; colorLoop = 0; }
if( secondHand == 30) { currentPalette = OceanColors_p; speed = 20; scale = 90; colorLoop = 0; }
if( secondHand == 35) { currentPalette = PartyColors_p; speed = 20; scale = 30; colorLoop = 1; }
if( secondHand == 40) { SetupRandomPalette(); speed = 20; scale = 20; colorLoop = 1; }
if( secondHand == 45) { SetupRandomPalette(); speed = 50; scale = 50; colorLoop = 1; }
if( secondHand == 50) { SetupRandomPalette(); speed = 90; scale = 90; colorLoop = 1; }
if( secondHand == 55) { currentPalette = RainbowStripeColors_p; speed = 30; scale = 20; colorLoop = 1; }
}
}
void SetupRandomPalette()
{
currentPalette = CRGBPalette16(
CHSV( random8(), 255, 32),
CHSV( random8(), 255, 255),
CHSV( random8(), 128, 255),
CHSV( random8(), 255, 255));
}
void SetupBlackAndWhiteStripedPalette()
{
// 'black out' all 16 palette entries...
fill_solid( currentPalette, 16, CRGB::Black);
// and set every fourth one to white.
currentPalette[0] = CRGB::White;
currentPalette[4] = CRGB::White;
currentPalette[8] = CRGB::White;
currentPalette[12] = CRGB::White;
}
// This function sets up a palette of purple and green stripes.
void SetupPurpleAndGreenPalette()
{
CRGB purple = CHSV( HUE_PURPLE, 255, 255);
CRGB green = CHSV( HUE_GREEN, 255, 255);
CRGB black = CRGB::Black;
currentPalette = CRGBPalette16(
green, green, black, black,
purple, purple, black, black,
green, green, black, black,
purple, purple, black, black );
}
uint16_t XY( uint8_t x, uint8_t y)
{
uint16_t i;
if( kMatrixSerpentineLayout == false) {
i = (y * kMatrixWidth) + x;
}
if( kMatrixSerpentineLayout == true) {
if( y & 0x01) {
// Odd rows run backwards
uint8_t reverseX = (kMatrixWidth - 1) - x;
i = (y * kMatrixWidth) + reverseX;
} else {
// Even rows run forwards
i = (y * kMatrixWidth) + x;
}
}
return i;
}</led_type,led_pin,color_order>
以下是需要从示例中需要更改的一些内容:
#define LED_PIN 9 #define BRIGHTNESS 96 #define LED_TYPE WS2811 #define COLOR_ORDER GRB const uint8_t kMatrixWidth = 16; const uint8_t kMatrixHeight = 8; const bool kMatrixSerpentineLayout = false;
根据连接的 Pin 更改LED_PIN,亮度也可以控制在0-255。kMatrix宽度和高度也需要根据矩阵布局(16x8)进行更改。kMatrixSerpentineLayout 需要设置为 false。
最基础的LED驱动就完成了,接下来可以做更大的矩阵,比如16x16 甚至更大,并使用软件将一些视频投影到矩阵上,目标是通过添加更多像素清楚地看到投影在矩阵上的视频或图像。