【花雕动手做】有趣好玩的音乐可视化系列小项目(22)--LED无限魔方  
  项目程序之六:一个用 FastLED 编程的LED无限魔方体  
 
 
 
			
			
			/*
   【花雕动手做】有趣好玩的音乐可视化系列小项目(22)--LED无限魔方
   项目程序之六:一个用 FastLED 编程的LED无限魔方体
 */
 
 #include <FastLED.h>
 
 #define LED_PIN               6
 #define LEDS_PER_SEGMENT      5
 #define SEGMENTS              12
 #define BRIGHTNESS            200
 #define NUM_LEDS              LEDS_PER_SEGMENT * SEGMENTS
 #define NUM_LEDS_WITH_SAFETY  NUM_LEDS + 1
 
 CRGB source1[NUM_LEDS_WITH_SAFETY];
 CRGB source2[NUM_LEDS_WITH_SAFETY];
 CRGB output[NUM_LEDS_WITH_SAFETY];
 
 uint8_t blendAmount = 0;
 uint8_t patternCounter = 0;
 uint8_t source1Pattern = 0;
 uint8_t source2Pattern = 1;
 bool useSource1 = false;
 
 void setup() {
   FastLED.addLeds<WS2812B, LED_PIN, GRB>(output, NUM_LEDS_WITH_SAFETY);
   FastLED.setBrightness(BRIGHTNESS);
   Serial.begin(57600);
 }
 
 void loop() {
   EVERY_N_MILLISECONDS(10) {
     blend(source1, source2, output, NUM_LEDS, blendAmount);   //在两个源之间混合
 
     if (useSource1) {
       if (blendAmount < 255) blendAmount++;                   //混合“向上”到源 2
     } else {
       if (blendAmount > 0) blendAmount--;                     //将“向下”混合到源 1
     }
   }
 
   EVERY_N_SECONDS(8) {
     nextPattern();
   }
 
   runPattern(source1Pattern, source1);                  //同时运行两种模式
   runPattern(source2Pattern, source2);
   
   FastLED.show();
 }
 
 void nextPattern() {
   patternCounter = (patternCounter + 1) % 5;
 
   if (useSource1) source1Pattern = patternCounter;
   else source2Pattern = patternCounter;
 
   useSource1 = !useSource1;
 }
 
 void runPattern(uint8_t pattern, CRGB *LEDarray) {
   switch (pattern) {
     case 0:
       rainbowComet(LEDarray);//彩虹彗星
       break;
     case 1:
       prettyNoise(LEDarray);//漂亮噪声
       break;
     case 2:
       randomStar(LEDarray);//随机星
       break;
     case 3:
       fillRainbow(LEDarray);//填充彩虹
       break;
     case 4:
       pixels(LEDarray);// 像素
       break;
   }
 }
 
 uint8_t xyz(uint8_t x, uint8_t y, uint8_t z) {
 
 /*边缘的坐标从 0 到 5。每条边缘只有 5 个“真实”像素,
    * 所以只有 1 - 5 个 LED。缺少顶点(角)。
    * 如果请求这些顶点之一,则返回一个不显示的安全像素。
    * 我们对立方体内部的坐标也做同样的事情,即不在边缘上。
    */
 
   uint8_t lps = LEDS_PER_SEGMENT;
   uint8_t safePx = NUM_LEDS;
 
   if ((x == 0 || x == lps + 1) && (y == 0 || y == lps + 1) && (z == 0 || z == lps + 1)) return safePx;
 
   // z 方向边缘
   if (x == 0        && y == 0)        return (8 * lps)  - z;      // Seg 7
   if (x == 0        && y == lps + 1)  return (12 * lps) - z;      // Seg 11
   if (x == lps + 1  && y == 0)        return (3 * lps)  + z - 1;  // Seg 3
   if (x == lps + 1  && y == lps + 1)  return (9 * lps)  + z - 1;  // Seg 9
 
   // y 方向边
   if (x == 0        && z == 0)        return y - 1;               // Seg 0
   if (x == 0        && z == lps + 1)  return (7 * lps)  - y;      // Seg 6
   if (x == lps + 1  && z == 0)        return (3 * lps)  - y;      // Seg 2
   if (x == lps + 1  && z == lps + 1)  return (4 * lps)  + y - 1;  // Seg 4
 
   // x 方向边
   if (y == 0        && z == 0)        return (8 * lps)  + x - 1;  // Seg 8
   if (y == 0        && z == lps + 1)  return (11 * lps) - x;      // Seg 10
   if (y == lps + 1  && z == 0)        return lps        + x - 1;  // Seg 1
   if (y == lps + 1  && z == lps + 1)  return (6 * lps)  - x;      // Seg 5
 
   //如果以上都不是,我们的坐标无效
   return safePx;
 }
 
 //------------ Patterns below ------------//
 
 void pixels(CRGB *LEDarray) {
   static uint8_t pos = 0;
   static uint8_t a = 0;
   static uint8_t b = 0;
 
   //填充所有像素并将它们混合在一起
   for (int c = 0; c <= LEDS_PER_SEGMENT + 1; c++) {
     LEDarray[xyz(a,b,c)] = blend(LEDarray[xyz(a,b,c)], CRGB::Orange, 128);
     LEDarray[xyz(a,c,b)] = blend(LEDarray[xyz(a,c,b)], CRGB::Magenta, 128);
     LEDarray[xyz(c,a,b)] = blend(LEDarray[xyz(c,a,b)], CRGB::Blue, 128);
   }
 
   EVERY_N_MILLISECONDS(33) {    
     //围绕正方形移动的坐标
     if(pos < 15) a++;
     else if (pos <= (LEDS_PER_SEGMENT * 2) + 1) b++;
     else if (pos <= (LEDS_PER_SEGMENT * 3) + 2) a--;
     else b--;
 
      //再次开始我们到达正方形的尽头
     pos = (pos + 1) % ((LEDS_PER_SEGMENT + 1) * 4);
   }
 
   fadeToBlackBy(LEDarray, NUM_LEDS, 10);
   
 }
 
 void fillRainbow(CRGB *LEDarray) {
   static uint8_t pos = 0;
   
   uint8_t noise = inoise8(millis()/5);
   fill_rainbow(LEDarray, LEDS_PER_SEGMENT, noise, 10);
 
   //复制到其他段
   for (int i = 0; i < SEGMENTS; i++) {
     memmove8(&LEDarray[LEDS_PER_SEGMENT * i], &LEDarray[0], LEDS_PER_SEGMENT * sizeof(CRGB));
   }
 
    //垂直柱子上下移动的白点
   LEDarray[xyz(0, 0, LEDS_PER_SEGMENT - pos)] = CRGB::White;
   LEDarray[xyz(0, LEDS_PER_SEGMENT + 1, pos)] = CRGB::White;
   LEDarray[xyz(LEDS_PER_SEGMENT + 1, LEDS_PER_SEGMENT + 1, LEDS_PER_SEGMENT - pos)] = CRGB::White;
   LEDarray[xyz(LEDS_PER_SEGMENT + 1, 0, pos)] = CRGB::White;
 
   EVERY_N_MILLISECONDS(20) {
     pos = (pos + 1) % LEDS_PER_SEGMENT;
   }
 }
 
 void rainbowComet(CRGB *LEDarray) {
   static uint8_t easeOutVal = 0;
   static uint8_t easeInVal  = 0;
 
   //使图案出现在两个段上
   uint8_t ledsPerSegment = LEDS_PER_SEGMENT * 2;
   uint8_t segments = SEGMENTS / 2;
 
   easeOutVal = ease8InOutQuad(easeInVal);
   easeInVal++;
 
   uint8_t pos = lerp8by8(0, ledsPerSegment, easeOutVal);
   uint8_t hue =  map(pos, 0, ledsPerSegment, 0, 230);
   
   LEDarray[pos] = CHSV(hue, 255, 255);
   fadeToBlackBy(LEDarray, ledsPerSegment, 20);
 
   //复制到其他段
   for (int i = 0; i < segments; i++) {
     memmove8(&LEDarray[ledsPerSegment * i], &LEDarray[0], ledsPerSegment * sizeof(CRGB));
   }
 }
 
 void randomStar(CRGB *LEDarray) {
   EVERY_N_MILLISECONDS(75) {
     LEDarray[random16(0, NUM_LEDS)] = CRGB::LightGrey;
   }
 
 
   for (int i = 0; i < NUM_LEDS; i++) {
     
     // 亮度
     uint8_t bNoise = inoise8(i * 100, millis());
     bNoise = constrain(bNoise, 50, 200);
     bNoise = map(bNoise, 50, 200, 20, 80);
 
     // 色调
     uint8_t hNoise = inoise8(i * 20, millis() / 5);
     hNoise = constrain(hNoise, 50, 200);
     hNoise = map(hNoise, 50, 200, 160, 192);
     
     if (LEDarray[i].g == 0) {
       LEDarray[i] = CHSV(hNoise, 255, bNoise);
     }
   }
   
   fadeToBlackBy(LEDarray, NUM_LEDS, 5);//淡入黑色(LED 阵列,NUM LEDS,5 个)
 }
 
 
 void prettyNoise(CRGB *LEDarray) {
   fill_noise16 (LEDarray, NUM_LEDS, 1, 0, 100, 1, 1, 50, millis() / 3, 5);
 } 复制代码