Kronimiciad

TwinkleFox

Aug 30th, 2023
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.87 KB | None | 0 0
  1. #include "FastLED.h"
  2.  
  3. #define NUM_STRIPS 4
  4. #define NUM_LEDS_PER_STRIP 22
  5. #define NUM_LEDS NUM_LEDS_PER_STRIP*NUM_STRIPS+9+10+12
  6. #define LED_TYPE WS2811
  7. #define COLOR_ORDER GRB
  8. #define DATA_PIN 5
  9. #define VOLTS 5
  10. #define MAX_MA 1500
  11.  
  12. CRGBArray<NUM_LEDS> leds[NUM_STRIPS];
  13.  
  14. // Overall twinkle speed.
  15. // 0 (VERY slow) to 8 (VERY fast).
  16. // 4, 5, and 6 are recommended, default is 4.
  17. #define TWINKLE_SPEED 2
  18.  
  19. // Overall twinkle density.
  20. // 0 (NONE lit) to 8 (ALL lit at once).
  21. // Default is 5.
  22. // #define TWINKLE_DENSITY 5
  23. #define TWINKLE_DENSITY 7
  24.  
  25. // How often to change color palettes.
  26. #define SECONDS_PER_PALETTE 30
  27. // Also: toward the bottom of the file is an array
  28. // called "ActivePaletteList" which controls which color
  29. // palettes are used; you can add or remove color palettes
  30. // from there freely.
  31.  
  32. // Background color for 'unlit' pixels
  33. // Can be set to CRGB::Black if desired.
  34. CRGB gBackgroundColor = CRGB::Black;
  35. // CRGB gBackgroundColor = CRGB::Parchment;
  36. // Example of dim incandescent fairy light background color
  37. // CRGB gBackgroundColor = CRGB(CRGB::FairyLight).nscale8_video(16);
  38.  
  39. CRGBPalette16 gCurrentPalette[NUM_STRIPS];
  40. CRGBPalette16 gTargetPalette[NUM_STRIPS];
  41.  
  42. int currentStrip = 0;
  43.  
  44. void setup() {
  45.  
  46. delay(3000); //safety startup delay
  47. FastLED.setMaxPowerInVoltsAndMilliamps(VOLTS, MAX_MA);
  48.  
  49. for(int i=0; i<NUM_STRIPS; i++) {
  50. FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds[i], NUM_LEDS).setCorrection(TypicalLEDStrip);
  51. chooseNextColorPalette(gTargetPalette[i]);
  52. }
  53. }
  54.  
  55.  
  56. void loop()
  57. {
  58.  
  59. for(int i=0; i<NUM_STRIPS; i++) {
  60. currentStrip = i;
  61.  
  62. EVERY_N_SECONDS(SECONDS_PER_PALETTE) {
  63. chooseNextColorPalette(gTargetPalette[i]);
  64. }
  65.  
  66. EVERY_N_MILLISECONDS(10) {
  67. nblendPaletteTowardPalette(gCurrentPalette[i], gTargetPalette[i], 12);
  68. }
  69.  
  70. drawTwinkles(leds[i]);
  71.  
  72. FastLED.show();
  73.  
  74. }
  75.  
  76. }
  77.  
  78.  
  79. // This function loops over each pixel, calculates the
  80. // adjusted 'clock' that this pixel should use, and calls
  81. // "CalculateOneTwinkle" on each pixel. It then displays
  82. // either the twinkle color of the background color,
  83. // whichever is brighter.
  84. void drawTwinkles(CRGBSet& L)
  85. {
  86. // "PRNG16" is the pseudorandom number generator
  87. // It MUST be reset to the same starting value each time
  88. // this function is called, so that the sequence of 'random'
  89. // numbers that it generates is (paradoxically) stable.
  90. uint16_t PRNG16 = 11337;
  91.  
  92. uint32_t clock32 = millis();
  93.  
  94. // Set up the background color, "bg".
  95. // the current palette are identical, then a deeply faded version of
  96. // that color is used for the background color
  97. CRGB bg = gBackgroundColor; // just use the explicitly defined background color
  98.  
  99. uint8_t backgroundBrightness = bg.getAverageLight();
  100.  
  101. for(CRGB& pixel: L) {
  102. PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
  103. uint16_t myclockoffset16= PRNG16; // use that number as clock offset
  104. PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
  105. // use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths)
  106. uint8_t myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF)>>4) + (PRNG16 & 0x0F)) & 0x0F) + 0x08;
  107. uint32_t myclock30 = (uint32_t)((clock32 * myspeedmultiplierQ5_3) >> 3) + myclockoffset16;
  108. uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel
  109.  
  110. // We now have the adjusted 'clock' for this pixel, now we call
  111. // the function that computes what color the pixel should be based
  112. // on the "brightness = f(time)" idea.
  113. CRGB c = computeOneTwinkle(myclock30, myunique8);
  114.  
  115. uint8_t cbright = c.getAverageLight();
  116. int16_t deltabright = cbright - backgroundBrightness;
  117. if(deltabright >= 32 || (!bg)) {
  118. // If the new pixel is significantly brighter than the background color,
  119. // use the new color.
  120. pixel = c;
  121. } else if(deltabright > 0) {
  122. // If the new pixel is just slightly brighter than the background color,
  123. // mix a blend of the new color and the background color
  124. pixel = blend(bg, c, deltabright * 8);
  125. } else {
  126. // if the new pixel is not at all brighter than the background color,
  127. // just use the background color.
  128. pixel = bg;
  129. }
  130. }
  131. }
  132.  
  133.  
  134. // This function takes a time in pseudo-milliseconds,
  135. // figures out brightness = f(time), and also hue = f(time)
  136. // The 'low digits' of the millisecond time are used as
  137. // input to the brightness wave function.
  138. // The 'high digits' are used to select a color, so that the color
  139. // does not change over the course of the fade-in, fade-out
  140. // of one cycle of the brightness wave function.
  141. // The 'high digits' are also used to determine whether this pixel
  142. // should light at all during this cycle, based on the TWINKLE_DENSITY.
  143. CRGB computeOneTwinkle(uint32_t ms, uint8_t salt)
  144. {
  145. uint16_t ticks = ms >> (8-TWINKLE_SPEED);
  146. uint8_t fastcycle8 = ticks;
  147. uint16_t slowcycle16 = (ticks >> 8) + salt;
  148. slowcycle16 += sin8(slowcycle16);
  149. slowcycle16 = (slowcycle16 * 2053) + 1384;
  150. uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8);
  151.  
  152. uint8_t bright = 0;
  153. if(((slowcycle8 & 0x0E)/2) < TWINKLE_DENSITY) {
  154. bright = attackDecayWave8(fastcycle8);
  155. }
  156.  
  157. uint8_t hue = slowcycle8 - salt;
  158. CRGB c;
  159. if(bright > 0) {
  160. c = ColorFromPalette(gCurrentPalette[currentStrip], hue, bright, NOBLEND);
  161. } else {
  162. c = CRGB::Black;
  163. }
  164. return c;
  165. }
  166.  
  167.  
  168. // This function is like 'triwave8', which produces a
  169. // symmetrical up-and-down triangle sawtooth waveform, except that this
  170. // function produces a triangle wave with a faster attack and a slower decay:
  171. //
  172. // / \
  173. // / \
  174. // / \
  175. // / \
  176. //
  177.  
  178. uint8_t attackDecayWave8(uint8_t i)
  179. {
  180. if(i < 86) {
  181. return i * 3;
  182. } else {
  183. i -= 86;
  184. return 255 - (i + (i/2));
  185. }
  186. }
  187.  
  188. // A mostly (dark) green palette with red berries.
  189. #define Holly_Green 0x00580c
  190. #define Holly_Red 0xB00402
  191. const TProgmemRGBPalette16 Holly_p FL_PROGMEM =
  192. { Holly_Green, Holly_Green, Holly_Green, Holly_Green,
  193. Holly_Green, Holly_Green, Holly_Green, Holly_Green,
  194. Holly_Green, Holly_Green, Holly_Green, Holly_Green,
  195. Holly_Green, Holly_Green, Holly_Green, Holly_Red
  196. };
  197.  
  198.  
  199. // Add or remove palette names from this list to control which color
  200. // palettes are used, and in what order.
  201. const TProgmemRGBPalette16* ActivePaletteList[][NUM_LEDS_PER_STRIP] = {
  202. {&Holly_p},
  203. {&Holly_p},
  204. {&Holly_p},
  205. {&Holly_p}
  206. };
  207.  
  208.  
  209. // Advance to the next color palette in the list (above).
  210. void chooseNextColorPalette(CRGBPalette16& pal)
  211. {
  212. const uint8_t numberOfPalettes = sizeof(ActivePaletteList) / sizeof(ActivePaletteList[0]);
  213. static uint8_t whichPalette = -1;
  214. whichPalette = addmod8(whichPalette, 1, numberOfPalettes);
  215.  
  216. pal = *(ActivePaletteList[whichPalette][currentStrip]);
  217. }
  218.  
Advertisement
Add Comment
Please, Sign In to add comment