Guest User

Untitled

a guest
Dec 17th, 2023
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.71 KB | Source Code | 0 0
  1. #include "FastLED.h"
  2.  
  3.  
  4. #define NUM_LEDS 344
  5. #define LED_TYPE WS2812B
  6. #define COLOR_ORDER GRB
  7. #define DATA_PIN 6
  8. //#define CLK_PIN 4
  9. #define VOLTS 5
  10. #define MAX_MA 5000
  11.  
  12. // TwinkleFOX: Twinkling 'holiday' lights that fade in and out.
  13. // Colors are chosen from a palette; a few palettes are provided.
  14. //
  15. // This December 2015 implementation improves on the December 2014 version
  16. // in several ways:
  17. // - smoother fading, compatible with any colors and any palettes
  18. // - easier control of twinkle speed and twinkle density
  19. // - supports an optional 'background color'
  20. // - takes even less RAM: zero RAM overhead per pixel
  21. // - illustrates a couple of interesting techniques (uh oh...)
  22. //
  23. // The idea behind this (new) implementation is that there's one
  24. // basic, repeating pattern that each pixel follows like a waveform:
  25. // The brightness rises from 0..255 and then falls back down to 0.
  26. // The brightness at any given point in time can be determined as
  27. // as a function of time, for example:
  28. // brightness = sine( time ); // a sine wave of brightness over time
  29. //
  30. // So the way this implementation works is that every pixel follows
  31. // the exact same wave function over time. In this particular case,
  32. // I chose a sawtooth triangle wave (triwave8) rather than a sine wave,
  33. // but the idea is the same: brightness = triwave8( time ).
  34. //
  35. // Of course, if all the pixels used the exact same wave form, and
  36. // if they all used the exact same 'clock' for their 'time base', all
  37. // the pixels would brighten and dim at once -- which does not look
  38. // like twinkling at all.
  39. //
  40. // So to achieve random-looking twinkling, each pixel is given a
  41. // slightly different 'clock' signal. Some of the clocks run faster,
  42. // some run slower, and each 'clock' also has a random offset from zero.
  43. // The net result is that the 'clocks' for all the pixels are always out
  44. // of sync from each other, producing a nice random distribution
  45. // of twinkles.
  46. //
  47. // The 'clock speed adjustment' and 'time offset' for each pixel
  48. // are generated randomly. One (normal) approach to implementing that
  49. // would be to randomly generate the clock parameters for each pixel
  50. // at startup, and store them in some arrays. However, that consumes
  51. // a great deal of precious RAM, and it turns out to be totally
  52. // unnessary! If the random number generate is 'seeded' with the
  53. // same starting value every time, it will generate the same sequence
  54. // of values every time. So the clock adjustment parameters for each
  55. // pixel are 'stored' in a pseudo-random number generator! The PRNG
  56. // is reset, and then the first numbers out of it are the clock
  57. // adjustment parameters for the first pixel, the second numbers out
  58. // of it are the parameters for the second pixel, and so on.
  59. // In this way, we can 'store' a stable sequence of thousands of
  60. // random clock adjustment parameters in literally two bytes of RAM.
  61. //
  62. // There's a little bit of fixed-point math involved in applying the
  63. // clock speed adjustments, which are expressed in eighths. Each pixel's
  64. // clock speed ranges from 8/8ths of the system clock (i.e. 1x) to
  65. // 23/8ths of the system clock (i.e. nearly 3x).
  66. //
  67. // On a basic Arduino Uno or Leonardo, this code can twinkle 300+ pixels
  68. // smoothly at over 50 updates per seond.
  69. //
  70. // -Mark Kriegsman, December 2015
  71.  
  72. CRGBArray<NUM_LEDS> leds;
  73. CRGBSet strips[] = {
  74. leds(0, 149), //overhead led strip
  75. leds(150, 174), //figure 1
  76. leds(175, 198), // figure 2
  77. leds(199, 222), // figure 3
  78. leds(223, 272), // letters
  79. leds(273, 296), //figure 4
  80. leds(297, 344), // figure 5
  81. };
  82. #define NUM_STRIPS (sizeof(strips) / sizeof(*strips))
  83.  
  84.  
  85. // Overall twinkle speed.
  86. // 0 (VERY slow) to 8 (VERY fast).
  87. // 4, 5, and 6 are recommended, default is 4.
  88. #define TWINKLE_SPEED 4
  89.  
  90. // Overall twinkle density.
  91. // 0 (NONE lit) to 8 (ALL lit at once).
  92. // Default is 5.
  93. #define TWINKLE_DENSITY 5
  94.  
  95. // How often to change color palettes.
  96. #define SECONDS_PER_PALETTE 30
  97. // Also: toward the bottom of the file is an array
  98. // called "ActivePaletteList" which controls which color
  99. // palettes are used; you can add or remove color palettes
  100. // from there freely.
  101.  
  102. // Background color for 'unlit' pixels
  103. // Can be set to CRGB::Black if desired.
  104. CRGB gBackgroundColor = CRGB::Black;
  105. // Example of dim incandescent fairy light background color
  106. // CRGB gBackgroundColor = CRGB(CRGB::FairyLight).nscale8_video(16);
  107.  
  108. // If AUTO_SELECT_BACKGROUND_COLOR is set to 1,
  109. // then for any palette where the first two entries
  110. // are the same, a dimmed version of that color will
  111. // automatically be used as the background color.
  112. #define AUTO_SELECT_BACKGROUND_COLOR 0
  113.  
  114. // If COOL_LIKE_INCANDESCENT is set to 1, colors will
  115. // fade out slighted 'reddened', similar to how
  116. // incandescent bulbs change color as they get dim down.
  117. #define COOL_LIKE_INCANDESCENT 1
  118.  
  119.  
  120. CRGBPalette16 gCurrentPalette[NUM_STRIPS];
  121. CRGBPalette16 gTargetPalette[NUM_STRIPS];
  122.  
  123. void setup() {
  124. delay( 3000 ); //safety startup delay
  125. FastLED.setMaxPowerInVoltsAndMilliamps( VOLTS, MAX_MA);
  126. FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS)
  127. .setCorrection(TypicalLEDStrip);
  128.  
  129. for (auto i = 0; i < NUM_STRIPS; i++)
  130. chooseNextColorPalette( gTargetPalette[i]);
  131. }
  132.  
  133.  
  134. void loop()
  135. {
  136. EVERY_N_SECONDS( SECONDS_PER_PALETTE ) {
  137. for (uint8_t i = 0; i < NUM_STRIPS; i++)
  138. chooseNextColorPalette( gTargetPalette[i] );
  139. }
  140.  
  141. EVERY_N_MILLISECONDS( 10 ) {
  142. for (uint8_t i = 0; i < NUM_STRIPS; i++)
  143. nblendPaletteTowardPalette( gCurrentPalette[i], gTargetPalette[i], 12);
  144. }
  145.  
  146. uint16_t offset = 0;
  147. for (auto& strip: strips) {
  148. drawTwinkles(strip, offset++);
  149. }
  150.  
  151. FastLED.show();
  152. }
  153.  
  154.  
  155. // This function loops over each pixel, calculates the
  156. // adjusted 'clock' that this pixel should use, and calls
  157. // "CalculateOneTwinkle" on each pixel. It then displays
  158. // either the twinkle color of the background color,
  159. // whichever is brighter.
  160. void drawTwinkles( CRGBSet& L, uint8_t strip)
  161. {
  162. // "PRNG16" is the pseudorandom number generator
  163. // It MUST be reset to the same starting value each time
  164. // this function is called, so that the sequence of 'random'
  165. // numbers that it generates is (paradoxically) stable.
  166. uint16_t PRNG16 = 11337 + strip;
  167.  
  168. uint32_t clock32 = millis();
  169.  
  170. // Set up the background color, "bg".
  171. // if AUTO_SELECT_BACKGROUND_COLOR == 1, and the first two colors of
  172. // the current palette are identical, then a deeply faded version of
  173. // that color is used for the background color
  174. CRGB bg;
  175. if( (AUTO_SELECT_BACKGROUND_COLOR == 1) &&
  176. (gCurrentPalette[strip][0] == gCurrentPalette[strip][1] )) {
  177. bg = gCurrentPalette[strip][0];
  178. uint8_t bglight = bg.getAverageLight();
  179. if( bglight > 64) {
  180. bg.nscale8_video( 16); // very bright, so scale to 1/16th
  181. } else if( bglight > 16) {
  182. bg.nscale8_video( 64); // not that bright, so scale to 1/4th
  183. } else {
  184. bg.nscale8_video( 86); // dim, scale to 1/3rd.
  185. }
  186. } else {
  187. bg = gBackgroundColor; // just use the explicitly defined background color
  188. }
  189.  
  190. uint8_t backgroundBrightness = bg.getAverageLight();
  191.  
  192. for( CRGB& pixel: L) {
  193. PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
  194. uint16_t myclockoffset16= PRNG16; // use that number as clock offset
  195. PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
  196. // use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths)
  197. uint8_t myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF)>>4) + (PRNG16 & 0x0F)) & 0x0F) + 0x08;
  198. uint32_t myclock30 = (uint32_t)((clock32 * myspeedmultiplierQ5_3) >> 3) + myclockoffset16;
  199. uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel
  200.  
  201. // We now have the adjusted 'clock' for this pixel, now we call
  202. // the function that computes what color the pixel should be based
  203. // on the "brightness = f( time )" idea.
  204. CRGB c = computeOneTwinkle( myclock30, myunique8, strip);
  205.  
  206. uint8_t cbright = c.getAverageLight();
  207. int16_t deltabright = cbright - backgroundBrightness;
  208. if( deltabright >= 32 || (!bg)) {
  209. // If the new pixel is significantly brighter than the background color,
  210. // use the new color.
  211. pixel = c;
  212. } else if( deltabright > 0 ) {
  213. // If the new pixel is just slightly brighter than the background color,
  214. // mix a blend of the new color and the background color
  215. pixel = blend( bg, c, deltabright * 8);
  216. } else {
  217. // if the new pixel is not at all brighter than the background color,
  218. // just use the background color.
  219. pixel = bg;
  220. }
  221. }
  222. }
  223.  
  224.  
  225. // This function takes a time in pseudo-milliseconds,
  226. // figures out brightness = f( time ), and also hue = f( time )
  227. // The 'low digits' of the millisecond time are used as
  228. // input to the brightness wave function.
  229. // The 'high digits' are used to select a color, so that the color
  230. // does not change over the course of the fade-in, fade-out
  231. // of one cycle of the brightness wave function.
  232. // The 'high digits' are also used to determine whether this pixel
  233. // should light at all during this cycle, based on the TWINKLE_DENSITY.
  234. CRGB computeOneTwinkle( uint32_t ms, uint8_t salt, uint8_t strip)
  235. {
  236. uint16_t ticks = ms >> (8-TWINKLE_SPEED);
  237. uint8_t fastcycle8 = ticks;
  238. uint16_t slowcycle16 = (ticks >> 8) + salt;
  239. slowcycle16 += sin8( slowcycle16);
  240. slowcycle16 = (slowcycle16 * 2053) + 1384;
  241. uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8);
  242.  
  243. uint8_t bright = 0;
  244. if( ((slowcycle8 & 0x0E)/2) < TWINKLE_DENSITY) {
  245. bright = attackDecayWave8( fastcycle8);
  246. }
  247.  
  248. uint8_t hue = slowcycle8 - salt;
  249. CRGB c;
  250. if( bright > 0) {
  251. c = ColorFromPalette( gCurrentPalette[strip], hue, bright, NOBLEND);
  252. if( COOL_LIKE_INCANDESCENT == 1 ) {
  253. coolLikeIncandescent( c, fastcycle8);
  254. }
  255. } else {
  256. c = CRGB::Black;
  257. }
  258. return c;
  259. }
  260.  
  261.  
  262. // This function is like 'triwave8', which produces a
  263. // symmetrical up-and-down triangle sawtooth waveform, except that this
  264. // function produces a triangle wave with a faster attack and a slower decay:
  265. //
  266. // / \
  267. // / \
  268. // / \
  269. // / \
  270. //
  271.  
  272. uint8_t attackDecayWave8( uint8_t i)
  273. {
  274. if( i < 86) {
  275. return i * 3;
  276. } else {
  277. i -= 86;
  278. return 255 - (i + (i/2));
  279. }
  280. }
  281.  
  282. // This function takes a pixel, and if its in the 'fading down'
  283. // part of the cycle, it adjusts the color a little bit like the
  284. // way that incandescent bulbs fade toward 'red' as they dim.
  285. void coolLikeIncandescent( CRGB& c, uint8_t phase)
  286. {
  287. if( phase < 128) return;
  288.  
  289. uint8_t cooling = (phase - 128) >> 4;
  290. c.g = qsub8( c.g, cooling);
  291. c.b = qsub8( c.b, cooling * 2);
  292. }
  293.  
  294. // A mostly red palette with green accents and white trim.
  295. // "CRGB::Gray" is used as white to keep the brightness more uniform.
  296. const TProgmemRGBPalette16 RedGreenWhite_p FL_PROGMEM =
  297. { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
  298. CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
  299. CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray,
  300. CRGB::Green, CRGB::Green, CRGB::Green, CRGB::Green };
  301.  
  302. // A mostly (dark) green palette with red berries.
  303. #define Holly_Green 0x00580c
  304. #define Holly_Red 0xB00402
  305. const TProgmemRGBPalette16 Holly_p FL_PROGMEM =
  306. { Holly_Green, Holly_Green, Holly_Green, Holly_Green,
  307. Holly_Green, Holly_Green, Holly_Green, Holly_Green,
  308. Holly_Green, Holly_Green, Holly_Green, Holly_Green,
  309. Holly_Green, Holly_Green, Holly_Green, Holly_Red
  310. };
  311.  
  312. // A red and white striped palette
  313. // "CRGB::Gray" is used as white to keep the brightness more uniform.
  314. const TProgmemRGBPalette16 RedWhite_p FL_PROGMEM =
  315. { CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
  316. CRGB::Gray, CRGB::Gray, CRGB::Gray, CRGB::Gray,
  317. CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
  318. CRGB::Gray, CRGB::Gray, CRGB::Gray, CRGB::Gray };
  319.  
  320. // A mostly blue palette with white accents.
  321. // "CRGB::Gray" is used as white to keep the brightness more uniform.
  322. const TProgmemRGBPalette16 BlueWhite_p FL_PROGMEM =
  323. { CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
  324. CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
  325. CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
  326. CRGB::Blue, CRGB::Gray, CRGB::Gray, CRGB::Gray };
  327.  
  328. // A pure "fairy light" palette with some brightness variations
  329. #define HALFFAIRY ((CRGB::FairyLight & 0xFEFEFE) / 2)
  330. #define QUARTERFAIRY ((CRGB::FairyLight & 0xFCFCFC) / 4)
  331. const TProgmemRGBPalette16 FairyLight_p FL_PROGMEM =
  332. { CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight,
  333. HALFFAIRY, HALFFAIRY, CRGB::FairyLight, CRGB::FairyLight,
  334. QUARTERFAIRY, QUARTERFAIRY, CRGB::FairyLight, CRGB::FairyLight,
  335. CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight };
  336.  
  337. // A palette of soft snowflakes with the occasional bright one
  338. const TProgmemRGBPalette16 Snow_p FL_PROGMEM =
  339. { 0x304048, 0x304048, 0x304048, 0x304048,
  340. 0x304048, 0x304048, 0x304048, 0x304048,
  341. 0x304048, 0x304048, 0x304048, 0x304048,
  342. 0x304048, 0x304048, 0x304048, 0xE0F0FF };
  343.  
  344. // A palette reminiscent of large 'old-school' C9-size tree lights
  345. // in the five classic colors: red, orange, green, blue, and white.
  346. #define C9_Red 0xB80400
  347. #define C9_Orange 0x902C02
  348. #define C9_Green 0x046002
  349. #define C9_Blue 0x070758
  350. #define C9_White 0x606820
  351. const TProgmemRGBPalette16 RetroC9_p FL_PROGMEM =
  352. { C9_Red, C9_Orange, C9_Red, C9_Orange,
  353. C9_Orange, C9_Red, C9_Orange, C9_Red,
  354. C9_Green, C9_Green, C9_Green, C9_Green,
  355. C9_Blue, C9_Blue, C9_Blue,
  356. C9_White
  357. };
  358.  
  359. // A cold, icy pale blue palette
  360. #define Ice_Blue1 0x0C1040
  361. #define Ice_Blue2 0x182080
  362. #define Ice_Blue3 0x5080C0
  363. const TProgmemRGBPalette16 Ice_p FL_PROGMEM =
  364. {
  365. Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
  366. Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
  367. Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
  368. Ice_Blue2, Ice_Blue2, Ice_Blue2, Ice_Blue3
  369. };
  370.  
  371.  
  372. // Add or remove palette names from this list to control which color
  373. // palettes are used, and in what order.
  374. const TProgmemRGBPalette16* ActivePaletteList[] = {
  375. &RetroC9_p,
  376. &BlueWhite_p,
  377. &RainbowColors_p,
  378. &FairyLight_p,
  379. &RedGreenWhite_p,
  380. &PartyColors_p,
  381. &RedWhite_p,
  382. &Snow_p,
  383. &Holly_p,
  384. &Ice_p
  385. };
  386.  
  387.  
  388. // Advance to the next color palette in the list (above).
  389. void chooseNextColorPalette( CRGBPalette16& pal)
  390. {
  391. const uint8_t numberOfPalettes = sizeof(ActivePaletteList) / sizeof(ActivePaletteList[0]);
  392. static uint8_t whichPalette = -1;
  393. whichPalette = addmod8( whichPalette, 1, numberOfPalettes);
  394.  
  395. pal = *(ActivePaletteList[whichPalette]);
  396. }
  397.  
Advertisement
Add Comment
Please, Sign In to add comment