很好的LED显示例子
代码:// TETRIS
#include <FastLED.h>
#include <LEDMatrix.h>
#include <LEDSprites.h>
#include <LEDText.h>
#include <FontMatrise.h>
#include "BluetoothSerial.h"
#define LED_PIN 15
#define COLOR_ORDER GRB
#define CHIPSET WS2812B
#define MATRIX_WIDTH 30
#define MATRIX_HEIGHT15
#define MATRIX_TYPE HORIZONTAL_MATRIX
// NOTE the '-' sign before the width, this is due to my leds matrix origin being on the right hand side
cLEDMatrix<MATRIX_WIDTH, -MATRIX_HEIGHT, MATRIX_TYPE> leds;
BluetoothSerial SerialBT;
#define TARGET_FRAME_TIME 15// Desired update rate, though if too many leds it will just run as fast as it can!
#define INITIAL_DROP_FRAMES20// Start of game block drop delay in frames
// Bluetooth input
enum btnInput {NONE, ROTATE, DOWN, LEFT, RIGHT};
btnInput currentInput = NONE;
const uint8_t TetrisIData[] =
{
// Frame 1
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(11110000),
// Frame 2
B8_3BIT(10000000),
B8_3BIT(10000000),
B8_3BIT(10000000),
B8_3BIT(10000000),
// Frame 3
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(11110000),
// Frame 4
B8_3BIT(10000000),
B8_3BIT(10000000),
B8_3BIT(10000000),
B8_3BIT(10000000)
};
const uint8_t TetrisIMask[] =
{
// Frame 1
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11110000),
// Frame 2
B8_1BIT(10000000),
B8_1BIT(10000000),
B8_1BIT(10000000),
B8_1BIT(10000000),
// Frame 3
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11110000),
// Frame 4
B8_1BIT(10000000),
B8_1BIT(10000000),
B8_1BIT(10000000),
B8_1BIT(10000000)
};
const uint8_t TetrisJData[] =
{
// Frame 1
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(22200000),
B8_3BIT(00200000),
// Frame 2
B8_3BIT(00000000),
B8_3BIT(02000000),
B8_3BIT(02000000),
B8_3BIT(22000000),
// Frame 3
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(20000000),
B8_3BIT(22200000),
// Frame 4
B8_3BIT(00000000),
B8_3BIT(22000000),
B8_3BIT(20000000),
B8_3BIT(20000000)
};
const uint8_t TetrisJMask[] =
{
// Frame 1
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11100000),
B8_1BIT(00100000),
// Frame 2
B8_1BIT(00000000),
B8_1BIT(01000000),
B8_1BIT(01000000),
B8_1BIT(11000000),
// Frame 3
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(10000000),
B8_1BIT(11100000),
// Frame 4
B8_1BIT(00000000),
B8_1BIT(11000000),
B8_1BIT(10000000),
B8_1BIT(10000000)
};
const uint8_t TetrisLData[] =
{
// Frame 1
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(33300000),
B8_3BIT(30000000),
// Frame 2
B8_3BIT(00000000),
B8_3BIT(33000000),
B8_3BIT(03000000),
B8_3BIT(03000000),
// Frame 3
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(00300000),
B8_3BIT(33300000),
// Frame 4
B8_3BIT(00000000),
B8_3BIT(30000000),
B8_3BIT(30000000),
B8_3BIT(33000000)
};
const uint8_t TetrisLMask[] =
{
// Frame 1
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11100000),
B8_1BIT(10000000),
// Frame 2
B8_1BIT(00000000),
B8_1BIT(11000000),
B8_1BIT(01000000),
B8_1BIT(01000000),
// Frame 3
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(00100000),
B8_1BIT(11100000),
// Frame 4
B8_1BIT(00000000),
B8_1BIT(10000000),
B8_1BIT(10000000),
B8_1BIT(11000000)
};
const uint8_t TetrisOData[] =
{
// Frame 1
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(44000000),
B8_3BIT(44000000),
// Frame 2
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(44000000),
B8_3BIT(44000000),
// Frame 3
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(44000000),
B8_3BIT(44000000),
// Frame 4
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(44000000),
B8_3BIT(44000000)
};
const uint8_t TetrisOMask[] =
{
// Frame 1
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11000000),
B8_1BIT(11000000),
// Frame 2
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11000000),
B8_1BIT(11000000),
// Frame 3
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11000000),
B8_1BIT(11000000),
// Frame 4
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11000000),
B8_1BIT(11000000)
};
const uint8_t TetrisSData[] =
{
// Frame 1
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(05500000),
B8_3BIT(55000000),
// Frame 2
B8_3BIT(00000000),
B8_3BIT(50000000),
B8_3BIT(55000000),
B8_3BIT(05000000),
// Frame 3
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(05500000),
B8_3BIT(55000000),
// Frame 4
B8_3BIT(00000000),
B8_3BIT(50000000),
B8_3BIT(55000000),
B8_3BIT(05000000)
};
const uint8_t TetrisSMask[] =
{
// Frame 1
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(01100000),
B8_1BIT(11000000),
// Frame 2
B8_1BIT(00000000),
B8_1BIT(10000000),
B8_1BIT(11000000),
B8_1BIT(01000000),
// Frame 3
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(01100000),
B8_1BIT(11000000),
// Frame 4
B8_1BIT(00000000),
B8_1BIT(10000000),
B8_1BIT(11000000),
B8_1BIT(01000000)
};
const uint8_t TetrisTData[] =
{
// Frame 1
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(66600000),
B8_3BIT(06000000),
// Frame 2
B8_3BIT(00000000),
B8_3BIT(06000000),
B8_3BIT(66000000),
B8_3BIT(06000000),
// Frame 3
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(06000000),
B8_3BIT(66600000),
// Frame 4
B8_3BIT(00000000),
B8_3BIT(60000000),
B8_3BIT(66000000),
B8_3BIT(60000000)
};
const uint8_t TetrisTMask[] =
{
// Frame 1
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11100000),
B8_1BIT(01000000),
// Frame 2
B8_1BIT(00000000),
B8_1BIT(01000000),
B8_1BIT(11000000),
B8_1BIT(01000000),
// Frame 3
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(01000000),
B8_1BIT(11100000),
// Frame 4
B8_1BIT(00000000),
B8_1BIT(10000000),
B8_1BIT(11000000),
B8_1BIT(10000000)
};
const uint8_t TetrisZData[] =
{
// Frame 1
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(77000000),
B8_3BIT(07700000),
// Frame 2
B8_3BIT(00000000),
B8_3BIT(07000000),
B8_3BIT(77000000),
B8_3BIT(70000000),
// Frame 3
B8_3BIT(00000000),
B8_3BIT(00000000),
B8_3BIT(77000000),
B8_3BIT(07700000),
// Frame 4
B8_3BIT(00000000),
B8_3BIT(07000000),
B8_3BIT(77000000),
B8_3BIT(70000000)
};
const uint8_t TetrisZMask[] =
{
// Frame 1
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11000000),
B8_1BIT(01100000),
// Frame 2
B8_1BIT(00000000),
B8_1BIT(01000000),
B8_1BIT(11000000),
B8_1BIT(10000000),
// Frame 3
B8_1BIT(00000000),
B8_1BIT(00000000),
B8_1BIT(11000000),
B8_1BIT(01100000),
// Frame 4
B8_1BIT(00000000),
B8_1BIT(01000000),
B8_1BIT(11000000),
B8_1BIT(10000000)
};
#define TETRIS_SPR_WIDTH4
#define TETRIS_SPR_HEIGHT 4
const uint8_t *TetrisSprData[] = { TetrisIData, TetrisJData, TetrisLData, TetrisOData, TetrisSData, TetrisTData, TetrisZData };
const uint8_t *TetrisSprMask[] = { TetrisIMask, TetrisJMask, TetrisLMask, TetrisOMask, TetrisSMask, TetrisTMask, TetrisZMask};
const struct CRGB TetrisColours[] = { CRGB(0, 255, 255), CRGB(0, 0, 255), CRGB(255, 165, 0), CRGB(255, 255, 0), CRGB(50, 205, 50), CRGB(255, 0, 255), CRGB(255, 0, 0) };
uint8_t PlayfieldData;
uint8_t PlayfieldMask;
uint8_t CompletedLinesData;
const struct CRGB CompletedLinesColour[] = { CRGB(255, 255, 255) };
cSprite Playfield, CompletedLines, CurrentBlock;
cLEDSprites Sprites(&leds);
unsigned char AttractMsg, GameOverMsg;
char BlankMsg;
cLEDText TetrisMsg;
uint8_t DropDelay;
boolean AttractMode, NextBlock;
int16_t TotalLines;
unsigned int HighScore = 0, LastScore;
uint16_t PlasmaTime, PlasmaShift;
uint32_t LoopDelayMS, LastLoop;
void setup()
{
Serial.begin(115200);
SerialBT.begin("ESP32Tetris");
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, leds.Size());
FastLED.setBrightness(200);
FastLED.clear(true);
FastLED.show();
memset(PlayfieldData, 0, sizeof(PlayfieldData));
memset(PlayfieldMask, 0, sizeof(PlayfieldMask));
Playfield.Setup(leds.Width(), leds.Height(), PlayfieldData, 1, _3BIT, TetrisColours, PlayfieldMask);
Playfield.SetPositionFrameMotionOptions(0, 0, 0, 0, 0, 0, 0, 0, 0);
Sprites.AddSprite(&Playfield);
memset(CompletedLinesData, 0, sizeof(CompletedLinesData));
CompletedLines.Setup(leds.Width(), TETRIS_SPR_HEIGHT, CompletedLinesData, 1, _1BIT, CompletedLinesColour, CompletedLinesData);
CompletedLines.SetPositionFrameMotionOptions(0, 0, 0, 0, 0, 0, 0, 0, 0);
TetrisMsg.SetFont(MatriseFontData);
sprintf((char *)BlankMsg, "%.*s", _min(((leds.Height() + TetrisMsg.FontHeight()) / (TetrisMsg.FontHeight() + 1)), (int)sizeof(BlankMsg) - 1), " ");
sprintf((char *)AttractMsg, "%sTETRIS%sSCORE %u%sHIGH %u%sANY BUTTON TO START%s", BlankMsg, BlankMsg, LastScore, BlankMsg, (int)HighScore, BlankMsg, BlankMsg);
TetrisMsg.Init(&leds, TetrisMsg.FontWidth() + 1, leds.Height(), (leds.Width() - TetrisMsg.FontWidth()) / 2, 0);
TetrisMsg.SetBackgroundMode(BACKGND_LEAVE);
TetrisMsg.SetScrollDirection(SCROLL_UP);
TetrisMsg.SetTextDirection(CHAR_UP);
TetrisMsg.SetFrameRate(1);
TetrisMsg.SetOptionsChangeMode(INSTANT_OPTIONS_MODE);
TetrisMsg.SetText(AttractMsg, strlen((const char *)AttractMsg));
AttractMode = true;
LoopDelayMS = TARGET_FRAME_TIME;
LastLoop = millis() - LoopDelayMS;
PlasmaShift = (random8(0, 5) * 32) + 64;
PlasmaTime = 0;
}
void loop()
{
if (abs(millis() - LastLoop) >= LoopDelayMS)
{
LastLoop = millis();
FastLED.clear();
// Fill background with dim plasma
#define PLASMA_X_FACTOR24
#define PLASMA_Y_FACTOR24
for (int16_t x=0; x<MATRIX_WIDTH; x++)
{
for (int16_t y=0; y<MATRIX_HEIGHT; y++)
{
int16_t r = sin16(PlasmaTime) / 256;
int16_t h = sin16(x * r * PLASMA_X_FACTOR + PlasmaTime) + cos16(y * (-r) * PLASMA_Y_FACTOR + PlasmaTime) + sin16(y * x * (cos16(-PlasmaTime) / 256) / 2);
leds(x, y) = CHSV((uint8_t)((h / 256) + 128), 255, 64);
}
}
uint16_t OldPlasmaTime = PlasmaTime;
PlasmaTime += PlasmaShift;
if (OldPlasmaTime > PlasmaTime)
PlasmaShift = (random8(0, 5) * 32) + 64;
if (AttractMode)
{
if (currentInput != NONE)
{
AttractMode = false;
memset(PlayfieldData, 0, sizeof(PlayfieldData));
memset(PlayfieldMask, 0, sizeof(PlayfieldMask));
Sprites.RemoveSprite(&CurrentBlock);
LastScore = 0;
TotalLines = 0;
DropDelay = INITIAL_DROP_FRAMES;
CurrentBlock.SetXChange(-1);
NextBlock = true;
currentInput = NONE;
}
}
else
{
if (Sprites.IsSprite(&CompletedLines))// We have highlighted complete lines, delay for visual effect
{
if (CompletedLines.GetXCounter() > 0)
CompletedLines.SetXCounter(CompletedLines.GetXCounter() - 1);
else
{
Sprites.RemoveSprite(&CompletedLines);
// Remove completed lines from playfield sprite
uint8_t *Data = PlayfieldData;
uint8_t *Mask = PlayfieldMask;
uint16_t Mbpl = (MATRIX_WIDTH + 7) / 8;
uint16_t Dbpl = Mbpl * _3BIT;
int16_t k;
for (int16_t i=(MATRIX_HEIGHT-1)*Dbpl,j=(MATRIX_HEIGHT-1)*Mbpl; i>=0; i-=Dbpl,j-=Mbpl)
{
for (k=0; k<MATRIX_WIDTH; k+=8)
{
if ((uint8_t)(0xff00 >> _min(MATRIX_WIDTH - k, 8)) != Mask)
break;
}
if (k >= MATRIX_WIDTH)
{
memmove(&Data, &Data, i);
memset(&Data, 0, Dbpl);
memmove(&Mask, &Mask, j);
memset(&Mask, 0, Mbpl);
i+=Dbpl;
j+=Mbpl;
}
}
}
}
else
{
if (CurrentBlock.GetXChange() >= 0) // We have a current block
{
// Check for user input
if ( currentInput == ROTATE )
{
currentInput = NONE;
if ((CurrentBlock.GetCurrentFrame() % 2) == 1)
{
if (CurrentBlock.GetXChange() == 0)
CurrentBlock.m_X = _min(CurrentBlock.m_X, MATRIX_WIDTH - TETRIS_SPR_WIDTH);
else if ((CurrentBlock.GetXChange() != 3) && (CurrentBlock.GetFlags() & SPRITE_EDGE_X_MAX))
--CurrentBlock.m_X;
}
CurrentBlock.IncreaseFrame();
Sprites.DetectCollisions(&CurrentBlock);
if (CurrentBlock.GetFlags() & SPRITE_COLLISION)
CurrentBlock.DecreaseFrame();
}
if ( currentInput == LEFT && (! (CurrentBlock.GetFlags() & SPRITE_EDGE_X_MIN)) )
{
currentInput = NONE;
CurrentBlock.m_X--;
Sprites.DetectCollisions(&CurrentBlock);
if (CurrentBlock.GetFlags() & SPRITE_COLLISION)
CurrentBlock.m_X++;
}
else if ( currentInput == RIGHT && (! (CurrentBlock.GetFlags() & SPRITE_EDGE_X_MAX)) )
{
currentInput = NONE;
CurrentBlock.m_X++;
Sprites.DetectCollisions(&CurrentBlock);
if (CurrentBlock.GetFlags() & SPRITE_COLLISION)
CurrentBlock.m_X--;
}
if ( currentInput == DOWN )
{
currentInput = NONE;
CurrentBlock.SetYCounter(1);
}
// Do block checks for bottom or collision
if (CurrentBlock.GetYCounter() <= 1)
{
if (CurrentBlock.GetFlags() & SPRITE_EDGE_Y_MIN)
NextBlock = true;
else
{
--CurrentBlock.m_Y;
Sprites.DetectCollisions(&CurrentBlock);
++CurrentBlock.m_Y;
if (CurrentBlock.GetFlags() & SPRITE_COLLISION)
{
// Block has collided check for game over
int16_t MaxY = MATRIX_HEIGHT - 2;
if ((CurrentBlock.GetCurrentFrame() % 2) == 1)
{
if (CurrentBlock.GetXChange() == 0)
MaxY -= 2;
else if (CurrentBlock.GetXChange() != 3)
MaxY -= 1;
}
else if (CurrentBlock.GetXChange() == 0)
++MaxY;
if (CurrentBlock.m_Y < MaxY)
NextBlock = true;
else
{
// Game over
CurrentBlock.SetYCounter(2);// Stop last block moving down!
AttractMode = true;
if (LastScore > HighScore)
{
HighScore = LastScore;
sprintf((char *)GameOverMsg, "%sGAME OVER%sNEW HIGH SCORE %u%s", BlankMsg, BlankMsg, LastScore, BlankMsg);
}
else
sprintf((char *)GameOverMsg, "%sGAME OVER%sSCORE %u%s", BlankMsg, BlankMsg, LastScore, BlankMsg);
sprintf((char *)AttractMsg, "%sTETRIS%sSCORE %u%sHIGH %u%sANY BUTTON TO START%s", BlankMsg, BlankMsg, LastScore, BlankMsg, HighScore, BlankMsg, BlankMsg);
TetrisMsg.SetText(GameOverMsg, strlen((char *)GameOverMsg));
TetrisMsg.SetBackgroundMode(BACKGND_DIMMING, 0x40);
}
}
}
}
}
if (NextBlock)// Start new block
{
if (CurrentBlock.GetXChange() >= 0) // We have a current block so add to playfield before creating new block
{
Playfield.Combine(CurrentBlock.m_X, CurrentBlock.m_Y, &CurrentBlock);
Sprites.RemoveSprite(&CurrentBlock);
// Make completed lines highlight sprite & score
memset(CompletedLinesData, 0, sizeof(CompletedLinesData));
CompletedLines.m_Y = -1;
uint8_t *Mask = PlayfieldMask;
uint16_t Mbpl = (MATRIX_WIDTH + 7) / 8;
int16_t j, numlines = 0;
for (int16_t i=(MATRIX_HEIGHT-1)*Mbpl, y=0; i>=0; i-=Mbpl,++y)
{
for (j=0; j<MATRIX_WIDTH; j+=8)
{
if ((uint8_t)(0xff00 >> _min(MATRIX_WIDTH - j, 8)) != Mask)
break;
}
if (j >= MATRIX_WIDTH)
{
if (CompletedLines.m_Y == -1)
CompletedLines.m_Y = y;
memset(&CompletedLinesData[((TETRIS_SPR_HEIGHT - 1) - (y - CompletedLines.m_Y)) * Mbpl], 0xff, Mbpl);
numlines++;
}
}
if (numlines > 0)
{
CompletedLines.SetXCounter(15);// Set delay for highlight display to 15 loops
Sprites.AddSprite(&CompletedLines);
}
LastScore += 1;
if (numlines == 1)
LastScore += 4;
else if (numlines == 2)
LastScore += 12;
else if (numlines == 3)
LastScore += 20;
else if (numlines == 4)
LastScore += 40;
TotalLines += numlines;
DropDelay = _max(1, INITIAL_DROP_FRAMES - (TotalLines / 5));
}
// Start new block
uint8_t j = random8(sizeof(TetrisSprData) / sizeof(TetrisSprData));
CurrentBlock.Setup(TETRIS_SPR_WIDTH, TETRIS_SPR_WIDTH, TetrisSprData, 4, _3BIT, TetrisColours, TetrisSprMask);
CurrentBlock.SetPositionFrameMotionOptions((MATRIX_WIDTH/2)-1, MATRIX_HEIGHT, 0, 0, 0, 0, -1, DropDelay, SPRITE_DETECT_COLLISION | SPRITE_DETECT_EDGE);
CurrentBlock.SetXChange(j);
Sprites.AddSprite(&CurrentBlock);
NextBlock = false;
}
Sprites.UpdateSprites();
}
}
Sprites.RenderSprites();
if (AttractMode)
{
if (TetrisMsg.UpdateText() == -1)
{
TetrisMsg.SetText(AttractMsg, strlen((char *)AttractMsg));
TetrisMsg.SetBackgroundMode(BACKGND_LEAVE);
Sprites.RemoveSprite(&CurrentBlock);
memset(PlayfieldData, 0, sizeof(PlayfieldData));
memset(PlayfieldMask, 0, sizeof(PlayfieldMask));
}
}
FastLED.show();
}
if(SerialBT.available()){
char keyPress = (char)SerialBT.read();
switch(keyPress) {
case 'w':
currentInput = ROTATE;
break;
case 'a':
currentInput = LEFT;
break;
case 's':
currentInput = DOWN;
break;
case 'd':
currentInput = RIGHT;
break;
}
Serial.println(currentInput);
}
} 只有背景的显示效果:
// TETRIS
#include <FastLED.h>
#include <LEDMatrix.h>
#include <LEDText.h>
#include <FontMatrise.h>
#define LED_PIN 15
#define COLOR_ORDER GRB
#define CHIPSET WS2812B
#define MATRIX_WIDTH 30
#define MATRIX_HEIGHT15
#define MATRIX_TYPE HORIZONTAL_MATRIX
// NOTE the '-' sign before the width, this is due to my leds matrix origin being on the right hand side
cLEDMatrix<MATRIX_WIDTH, -MATRIX_HEIGHT, MATRIX_TYPE> leds;
#define TARGET_FRAME_TIME 15// Desired update rate, though if too many leds it will just run as fast as it can!
uint16_t PlasmaTime, PlasmaShift;
void setup()
{
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, leds.Size());
FastLED.setBrightness(200);
FastLED.clear(true);
FastLED.show();
PlasmaShift = (random8(0, 5) * 32) + 64;
PlasmaTime = 0;
}
void loop()
{
FastLED.clear();
// Fill background with dim plasma
#define PLASMA_X_FACTOR24
#define PLASMA_Y_FACTOR24
for (int16_t x=0; x<MATRIX_WIDTH; x++)
{
for (int16_t y=0; y<MATRIX_HEIGHT; y++)
{
int16_t r = sin16(PlasmaTime) / 256;
int16_t h = sin16(x * r * PLASMA_X_FACTOR + PlasmaTime) + cos16(y * (-r) * PLASMA_Y_FACTOR + PlasmaTime) + sin16(y * x * (cos16(-PlasmaTime) / 256) / 2);
leds(x, y) = CHSV((uint8_t)((h / 256) + 128), 255, 64);
}
}
uint16_t OldPlasmaTime = PlasmaTime;
PlasmaTime += PlasmaShift;
if (OldPlasmaTime > PlasmaTime)
PlasmaShift = (random8(0, 5) * 32) + 64;
FastLED.show();
delay(10);
} // TETRIS
#include <FastLED.h>
#include <LEDMatrix.h>
#define LED_PIN 15
#define COLOR_ORDER GRB
#define CHIPSET WS2812B
#define MATRIX_WIDTH 30
#define MATRIX_HEIGHT15
#define MATRIX_TYPE HORIZONTAL_MATRIX
// NOTE the '-' sign before the width, this is due to my leds matrix origin being on the right hand side
cLEDMatrix<MATRIX_WIDTH, -MATRIX_HEIGHT, MATRIX_TYPE> leds;
#define TARGET_FRAME_TIME 15// Desired update rate, though if too many leds it will just run as fast as it can!
uint16_t PlasmaTime, PlasmaShift;
void setup()
{
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, leds.Size());
FastLED.setBrightness(200);
FastLED.clear(true);
FastLED.show();
PlasmaShift = (random8(0, 5) * 32) + 64;
PlasmaTime = 0;
}
void loop()
{
// Fill background with dim plasma
#define PLASMA_X_FACTOR24
#define PLASMA_Y_FACTOR24
for (int16_t x=0; x<MATRIX_WIDTH; x++)
{
for (int16_t y=0; y<MATRIX_HEIGHT; y++)
{
int16_t r = sin16(PlasmaTime) / 256;
int16_t h = sin16(x * r * PLASMA_X_FACTOR + PlasmaTime) + cos16(y * (-r) * PLASMA_Y_FACTOR + PlasmaTime) + sin16(y * x * (cos16(-PlasmaTime) / 256) / 2);
leds(x, y) = CHSV((uint8_t)((h / 256) + 128), 255, 64);
}
}
uint16_t OldPlasmaTime = PlasmaTime;
PlasmaTime += PlasmaShift;
if (OldPlasmaTime > PlasmaTime)
PlasmaShift = (random8(0, 5) * 32) + 64;
FastLED.show();
delay(50);
} 限制颜色和平滑的效果(不理想)
// TETRIS
#include <FastLED.h>
#include <LEDMatrix.h>
#define LED_PIN 15
#define COLOR_ORDER GRB
#define CHIPSET WS2812B
#define MATRIX_WIDTH 30
#define MATRIX_HEIGHT15
#define MATRIX_TYPE HORIZONTAL_MATRIX
cLEDMatrix<MATRIX_WIDTH, -MATRIX_HEIGHT, MATRIX_TYPE> leds;
#define TARGET_FRAME_TIME 15
uint16_t PlasmaTime, PlasmaShift;
void setup() {
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, leds.Size());
FastLED.setBrightness(200);
FastLED.clear(true);
PlasmaShift = (random8(0, 5) * 16) + 32;// 降低变化速度
PlasmaTime = 0;
}
void loop() {
static uint8_t lastHue = 128;// 用于色相平滑过渡
FastLED.clear();
// 更平滑的波形参数
#define PLASMA_X_FACTOR16// 降低X/Y方向波形频率
#define PLASMA_Y_FACTOR16
#define HUE_START96 // 青色
#define HUE_END 220 // 紫色
for (int16_t x=0; x<MATRIX_WIDTH; x++) {
for (int16_t y=0; y<MATRIX_HEIGHT; y++) {
// 使用更平滑的波形组合
int16_t r = sin16(PlasmaTime * 0.7) / 512;// 降低振幅变化速度
int16_t h = sin16(x * PLASMA_X_FACTOR + PlasmaTime * 0.5)
+ cos16(y * PLASMA_Y_FACTOR + PlasmaTime * 0.3)
+ sin16((x + y) * 64 + PlasmaTime * 0.4);// 简化第三项波形
// 非线性映射 + 低通滤波平滑色相
uint8_t targetHue = map(h, -32768, 32767, HUE_START, HUE_END);
uint8_t hue = (targetHue * 0.3) + (lastHue * 0.7);// 指数平滑
lastHue = hue;
leds(x, y) = CHSV(hue, 200, 100);
}
}
// 更缓慢的时间推进
PlasmaTime += PlasmaShift;
if (PlasmaTime % 512 == 0)// 定期重置避免溢出
PlasmaShift = random8(0, 5) * 16 + 32;
FastLED.show();
delay(20);
} 随机变化的效果:
// 风场参数
const uint8_t scale = 25; // 缩小缩放因子扩大波纹范围
const uint8_t speed = 2; // 降低运动速度
const int8_t windDirection = 1;
const uint8_t blurAmount = 48;// 新增模糊系数
uint16_t z = 0;
// 优化的噪声生成函数
void generateNoise(uint8_t *noiseData, uint16_t zOffset) {
for(uint8_t y=0; y<MATRIX_HEIGHT; y++) {
for(uint8_t x=0; x<MATRIX_WIDTH; x++) {
uint8_t xOffset = windDirection * beatsin8(
3, // 降低波浪频率
0, 15, // 减小振幅范围
0,
(x * 2 + y * 3) // 优化相位关系
);
noiseData = inoise8(
(x + xOffset) * scale,
y * scale * 1.2, // Y轴增加缩放差异
zOffset
);
}
}
}
void wind_vision()
{
static uint32_t lastUpdate = 0;
static uint8_t blendVal = 0;
if(millis() - lastUpdate > 30) {
lastUpdate = millis();
// 双缓冲噪声生成
uint8_t noiseData1;
uint8_t noiseData2;
// 生成两帧噪声数据
generateNoise(noiseData1, z);
generateNoise(noiseData2, z + 50); // 50个时间单位偏移
// 混合两帧数据
for(int i=0; i<NUM_LEDS; i++) {
uint8_t finalNoise = blend8(noiseData1, noiseData2, blendVal);
// 扩展颜色映射范围
uint8_t hue = map(finalNoise, 40, 210, 180, 255); // 颜色范围180-255
uint8_t val = map(finalNoise, 60, 190, 50, 220);// 保持亮度动态
leds = CHSV(hue, 245, val); // 略微降低饱和度
}
// 应用二维模糊
blur2d(leds, MATRIX_WIDTH, MATRIX_HEIGHT, blurAmount);
z += speed;
blendVal += 3; // 控制混合速度
FastLED.show();
}
}
#include <FastLED.h>
// ========== 硬件配置 ==========
#define LED_PIN 15
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define MATRIX_WIDTH30
#define MATRIX_HEIGHT 15
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
CRGB leds;
// ========== 动画参数 ==========
#define FRAME_RATE 30
#define NOISE_SCALE 0.1f
#define FLOW_SPEED 0.8f
#define HUE_SPEED 0.02f
#define BRIGHTNESS 80
// ========== 全局变量 ==========
float z;
uint8_t hue_base;
// ========== 完整的perm数组 ==========
const uint8_t perm = {
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225,
140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122,
60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169,
200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212,
207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241,
81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93,
222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180
};
// ========== 修改后的噪声函数(重命名避免冲突)==========
uint8_t custom_noise(uint16_t x, uint16_t y, uint16_t z) {
uint8_t a= perm[(x>>8)&0xFF] + (y>>8);
uint8_t b= perm[(y>>8)&0xFF] + (z>>8);
uint8_t aa = perm + (z>>8);
uint8_t ba = perm + (x>>8);
uint8_t u = x & 0xFF;
uint8_t v = y & 0xFF;
return lerp8by8(lerp8by8(perm, perm, u),
lerp8by8(perm, perm, u), v);
}
// ========== 坐标映射函数 ==========
uint16_t XY(uint8_t x, uint8_t y) {
if(y % 2 == 0) {
return y * MATRIX_WIDTH + x;
} else {
return (y + 1) * MATRIX_WIDTH - x - 1;
}
}
// ========== 主渲染函数(参数类型修正)==========
void renderFrame() {
static float xOffset = 0;
static float yOffset = 0;
xOffset += FLOW_SPEED * 0.7;
yOffset += FLOW_SPEED * 0.5;
hue_base += HUE_SPEED * 255;
z += 0.05;
for(uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
for(uint8_t x = 0; x < MATRIX_WIDTH; x++) {
// 转换为整数参数
uint16_t nx = (uint16_t)(x * NOISE_SCALE * 256 + xOffset * 256);
uint16_t ny = (uint16_t)(y * NOISE_SCALE * 256 + yOffset * 256);
uint16_t nz = (uint16_t)(z * 256);
uint8_t noise = (
custom_noise(nx, ny, nz) * 0.6 +
custom_noise(nx*2, ny*2, nz) * 0.4
);
CRGB color = CHSV(noise + hue_base, 255, noise);
leds = color;
}
}
}
void setup() {
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
randomSeed(analogRead(0));
z = random(65536);
}
void loop() {
static uint32_t lastFrame = 0;
uint32_t frameInterval = 1000 / FRAME_RATE;
if(millis() - lastFrame >= frameInterval) {
renderFrame();
FastLED.show();
lastFrame = millis();
}
yield();
} keer_zu 发表于 2025-5-23 22:29
颜色受到限制的版本:
#include <FastLED.h>
// ========== 硬件配置 ==========
#define LED_PIN 15
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define MATRIX_WIDTH30
#define MATRIX_HEIGHT 15
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
CRGB leds;
// ========== 动画参数 ==========
#define FRAME_RATE 30
#define NOISE_SCALE 0.05f // 更细腻的噪声图案
#define FLOW_SPEED 0.3f // 慢速流动
#define HUE_SPEED 0.005f // 缓慢色调变化
#define BRIGHTNESS 80 // 中等亮度
// ========== 全局变量 ==========
float z;
uint8_t hue_base;
// ========== perm数组(保持不变)==========
const uint8_t perm = {
151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,
8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,
35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,
134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,
55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,
18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,
250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,
189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,
172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,
228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,
49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,
236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
// ========== 自定义噪声函数 ==========
uint8_t custom_noise(uint16_t x, uint16_t y, uint16_t z) {
uint8_t a= perm[(x>>8)&0xFF] + (y>>8);
uint8_t b= perm[(y>>8)&0xFF] + (z>>8);
uint8_t aa = perm + (z>>8);
uint8_t ba = perm + (x>>8);
uint8_t u = x & 0xFF;
uint8_t v = y & 0xFF;
return lerp8by8(lerp8by8(perm, perm, u),
lerp8by8(perm, perm, u), v);
}
// ========== 蛇形映射函数 ==========
uint16_t XY(uint8_t x, uint8_t y) {
if(y % 2 == 0) {
return y * MATRIX_WIDTH + x;
} else {
return (y + 1) * MATRIX_WIDTH - x - 1;
}
}
// ========== 主渲染函数 ==========
void renderFrame() {
static float xOffset = 0;
static float yOffset = 0;
// 缓慢更新位置参数
xOffset += FLOW_SPEED * 0.7;
yOffset += FLOW_SPEED * 0.5;
hue_base += HUE_SPEED * 255;
z += 0.02;
for(uint8_t y = 0; y < MATRIX_HEIGHT; y++) {
for(uint8_t x = 0; x < MATRIX_WIDTH; x++) {
// 生成噪声参数
uint16_t nx = (uint16_t)(x * NOISE_SCALE * 256 + xOffset * 256);
uint16_t ny = (uint16_t)(y * NOISE_SCALE * 256 + yOffset * 256);
uint16_t nz = (uint16_t)(z * 256);
// 混合噪声层
uint8_t noise = (
custom_noise(nx, ny, nz) * 0.6 +
custom_noise(nx*2, ny*2, nz) * 0.4
);
// 颜色处理(限制在100-220 Hue范围)
uint8_t rawHue = noise + hue_base;
uint8_t scaledHue = scale8(rawHue, 120) + 100; // 120 = 60*2
CRGB color = CHSV(scaledHue, 200, noise); // 适当降低饱和度
leds = color;
}
}
}
// ========== 初始化 ==========
void setup() {
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
randomSeed(analogRead(0));
z = random(65536);// 随机初始Z值
}
// ========== 主循环 ==========
void loop() {
static uint32_t lastFrame = 0;
uint32_t frameInterval = 1000 / FRAME_RATE;
if(millis() - lastFrame >= frameInterval) {
renderFrame();
FastLED.show();
lastFrame = millis();
}
yield();
}
页:
[1]