Guest User

Untitled

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