/ Jack_O_LED_trix / Jack_O_LED_trix.ino
Jack_O_LED_trix.ino
1 // SPDX-FileCopyrightText: 2018 Anne Barela for Adafruit Industries 2 // 3 // SPDX-License-Identifier: MIT 4 5 /* This is the FastLED library NoisePlusPalette example code incorporating a momentary 6 push button to cycle between modes for the Jack-o-LED-trix project. 7 8 You should wire a momentary push button to connect from ground to a digital IO pin. 9 In this example, wire the button to ground and pin 11. 10 11 FastLED has a number of built in "palettes" to choose from: 12 RainbowColors_p is all the colors of the rainbow 13 PartyColors_p is all the colors of the rainbow minus greens 14 RainbowStripeColors_p is all the colors of the rainbow divided into stripes 15 HeatColors_p is reds and yellows, white, and black 16 LavaColors_p is more reds and orangey colors 17 ForestColors_p is greens and yellows 18 OceanColors_p is lots of blues and aqua colors 19 CloudColors_p is blues and white 20 FastLED also provides a number of easy ways to create you own personalized palettes, 21 see the "HalloweenPalette_p" to personalize your own colors. 22 23 There are also ways to create other palettes using functions, 24 see "SetupCandyCornPalette()" & "SetupBlackAndWhiteStripedPalette()" to personalize 25 your own colors. 26 */ 27 28 #include <FastLED.h> 29 #include "colorutils.h" 30 #include "colorpalettes.h" 31 32 #define BRIGHTNESS 128 33 34 //Define the type of pixels you are using on the next line here. 35 //If you are using a strand or two of WS2801 pixels from Adafruit, update the chipset type to WS2801. 36 #define LED_TYPE WS2811 37 38 //You may need to adjust your color order to "GRB" instead of "RGB" below. 39 #define COLOR_ORDER RGB 40 41 //If you are using 4-pin LEDs, you will need to uncomment and define the CLOCK_PIN 42 #define DATA_PIN 6 43 //#define CLOCK_PIN # 44 45 #define BUTTON_PIN 11 // button is connected to pin 11 and GND 46 #define UPDATES_PER_SECOND 100 47 48 //This sketch is set up for a matrix of 8 pixels wide and 6 pixels high. Update to match your matrix. 49 const uint8_t kMatrixWidth = 8; 50 const uint8_t kMatrixHeight = 6; 51 const bool kMatrixSerpentineLayout = true; 52 53 #define NUM_LEDS (kMatrixWidth * kMatrixHeight) //no need to define the number of LEDS - here's the math! 54 #define MAX_DIMENSION ((kMatrixWidth>kMatrixHeight) ? kMatrixWidth : kMatrixHeight) 55 56 // The leds 57 CRGB leds[kMatrixWidth * kMatrixHeight]; 58 59 uint8_t gHue = 0; // rotating "base color" used by many of the patterns 60 int ledMode = 0; 61 62 // The 16 bit version of our coordinates 63 static uint16_t x; 64 static uint16_t y; 65 static uint16_t z; 66 67 // We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll 68 // use the z-axis for "time". speed determines how fast time moves forward. Try 69 // 1 for a very slow moving effect, or 60 for something that ends up looking like 70 // water. 71 uint16_t speed = 10; // speed is set dynamically once we've started up 72 73 // Scale determines how far apart the pixels in our noise matrix are. Try 74 // changing these values around to see how it affects the motion of the display. The 75 // higher the value of scale, the more "zoomed out" the noise will be. A value 76 // of 1 will be so zoomed in, you'll mostly see solid colors. 77 uint16_t scale = 50; // scale is set dynamically once we've started up 78 79 // This is the array that we keep our computed noise values in 80 uint8_t noise[MAX_DIMENSION][MAX_DIMENSION]; 81 82 CRGBPalette16 currentPalette( RainbowColors_p ); 83 uint8_t colorLoop = 0; 84 85 TBlendType currentBlending; 86 87 const TProgmemPalette16 HalloweenPalette_p PROGMEM = 88 { 89 CRGB:: OrangeRed, 90 CRGB:: Gold, 91 CRGB:: Purple, 92 CRGB:: Gold, 93 94 CRGB:: OrangeRed, 95 CRGB:: Gold, 96 CRGB:: Purple, 97 CRGB:: OrangeRed, 98 99 CRGB:: Gold, 100 CRGB:: Purple, 101 CRGB:: Gold, 102 CRGB:: OrangeRed, 103 104 CRGB:: Gold, 105 CRGB:: Purple, 106 CRGB:: Gold, 107 CRGB:: OrangeRed, 108 }; 109 110 111 unsigned long keyPrevMillis = 0; 112 const unsigned long keySampleIntervalMs = 25; 113 byte longKeyPressCountMax = 80; // 80 * 25 = 2000 ms 114 byte longKeyPressCount = 0; 115 116 byte prevKeyState = HIGH; // button is active low 117 118 void setup() { 119 delay(3000); 120 121 //If you are using 3-pin LEDs, uncomment the next line: 122 FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); 123 124 //If you are using 4-pin LEDs, uncomment the next line: 125 //FastLED.addLeds<LED_TYPE, DATA_PIN, CLOCK_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); 126 127 FastLED.setBrightness(BRIGHTNESS); 128 currentBlending; 129 pinMode(BUTTON_PIN, INPUT_PULLUP); 130 131 // Initialize our coordinates to some random values 132 x = random16(); 133 y = random16(); 134 z = random16(); 135 } 136 137 // Fill the x/y array of 8-bit noise values using the inoise8 function. 138 void fillnoise8() { 139 // If we're runing at a low "speed", some 8-bit artifacts become visible 140 // from frame-to-frame. In order to reduce this, we can do some fast data-smoothing. 141 // The amount of data smoothing we're doing depends on "speed". 142 uint8_t dataSmoothing = 0; 143 if( speed < 50) { 144 dataSmoothing = 200 - (speed * 4); 145 } 146 147 for(int i = 0; i < MAX_DIMENSION; i++) { 148 int ioffset = scale * i; 149 for(int j = 0; j < MAX_DIMENSION; j++) { 150 int joffset = scale * j; 151 152 uint8_t data = inoise8(x + ioffset,y + joffset,z); 153 154 // The range of the inoise8 function is roughly 16-238. 155 // These two operations expand those values out to roughly 0..255 156 // You can comment them out if you want the raw noise data. 157 data = qsub8(data,16); 158 data = qadd8(data,scale8(data,39)); 159 160 if( dataSmoothing ) { 161 uint8_t olddata = noise[i][j]; 162 uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing); 163 data = newdata; 164 } 165 166 noise[i][j] = data; 167 } 168 } 169 170 z += speed; 171 172 // apply slow drift to X and Y, just for visual variation. 173 x += speed / 8; 174 y -= speed / 16; 175 } 176 177 void mapNoiseToLEDsUsingPalette() 178 { 179 static uint8_t ihue=0; 180 181 for(int i = 0; i < kMatrixWidth; i++) { 182 for(int j = 0; j < kMatrixHeight; j++) { 183 // We use the value at the (i,j) coordinate in the noise 184 // array for our brightness, and the flipped value from (j,i) 185 // for our pixel's index into the color palette. 186 187 uint8_t index = noise[j][i]; 188 uint8_t bri = noise[i][j]; 189 190 // if this palette is a 'loop', add a slowly-changing base value 191 if( colorLoop) { 192 index += ihue; 193 } 194 195 // brighten up, as the color palette itself often contains the 196 // light/dark dynamic range desired 197 if( bri > 127 ) { 198 bri = 255; 199 } else { 200 bri = dim8_raw( bri * 2); 201 } 202 203 CRGB color = ColorFromPalette( currentPalette, index, bri); 204 leds[XY(i,j)] = color; 205 } 206 } 207 208 ihue+=1; 209 } 210 211 void loop() { 212 213 byte currKeyState = digitalRead(BUTTON_PIN); 214 215 if ((prevKeyState == LOW) && (currKeyState == HIGH)) { 216 shortKeyPress(); 217 } 218 prevKeyState = currKeyState; 219 220 static uint8_t startIndex = 0; 221 startIndex = startIndex + 1; /* motion speed */ 222 223 // generate noise data 224 fillnoise8(); 225 226 //The group of colors in a palette are sent through a strip of LEDS in speed and step increments youve chosen 227 //You can change the SPEED and STEPS to make things look exactly how you want 228 //SPEED refers to how fast the colors move. 229 //Try 1 for a very slow moving effect, or 60 for something that ends up looking like water. 230 //SCALE refers to how zoomed in we are. 231 //Try changing these values around to see how it affects the motion of the display. 232 //The higher the value of scale, the more "zoomed out" the noise will be. 233 //A value of 1 will be so zoomed in, you'll mostly see solid colors. 234 235 // convert the noise data to colors in the LED array using the current palette 236 mapNoiseToLEDsUsingPalette(); 237 238 switch (ledMode) { 239 case 0: 240 {currentPalette = RainbowColors_p; speed = 25; scale = 25; colorLoop = 0; } 241 break; 242 243 case 1: 244 {currentPalette = HeatColors_p; speed = 20; scale = 50; colorLoop = 2; } 245 break; 246 247 case 2: 248 {SetupBlackAndWhiteStripedPalette(); speed = 20; scale = 100; colorLoop = 1; } 249 break; 250 251 case 3: 252 {currentPalette = LavaColors_p; speed = 10; scale = 25; colorLoop = 0; } 253 break; 254 255 case 4: 256 {currentPalette = HalloweenPalette_p; speed = 20; scale = 20; colorLoop = 1; } 257 break; 258 259 case 5: 260 {SetupCandyCornPalette(); speed = 15; scale = 30; colorLoop = 1; } 261 break; 262 } 263 264 //FillLEDsFromPaletteColors( startIndex); 265 LEDS.show(); 266 delay(1000/speed); 267 } 268 269 void shortKeyPress() { 270 ledMode++; 271 if (ledMode > 5) { 272 ledMode=0; 273 } 274 } 275 276 // This function sets up a palette of black and white stripes, 277 // using code. Since the palette is effectively an array of 278 // sixteen CRGB colors, the various fill_* functions can be used 279 // to set them up. 280 void SetupBlackAndWhiteStripedPalette() 281 { 282 // 'black out' all 16 palette entries... 283 fill_solid( currentPalette, 16, CRGB::Black); 284 // and set every fourth one to White or Gray. 285 currentPalette[0] = CRGB::White; 286 currentPalette[4] = CRGB::Gray; 287 currentPalette[8] = CRGB::White; 288 currentPalette[12] = CRGB::Gray; 289 290 } 291 292 // This function sets up a palette of candy corn colors 293 void SetupCandyCornPalette() 294 { 295 fill_solid( currentPalette, 16, CRGB::Black); 296 // set half of the LEDs to the colors selected here. This palette incorporates a lot of black 297 currentPalette[0] = CRGB::Orange; 298 currentPalette[1] = CRGB::Yellow; 299 currentPalette[2] = CRGB::Red; 300 currentPalette[3] = CRGB::OrangeRed; 301 302 currentPalette[8] = CRGB::Yellow; 303 currentPalette[9] = CRGB::OrangeRed; 304 currentPalette[10] = CRGB::Orange; 305 currentPalette[11] = CRGB::Red; 306 307 } 308 309 // Mark's xy coordinate mapping code. See the XYMatrix for more information on it. 310 // 311 uint16_t XY( uint8_t x, uint8_t y) 312 { 313 uint16_t i; 314 if( kMatrixSerpentineLayout == false) { 315 i = (y * kMatrixWidth) + x; 316 } 317 if( kMatrixSerpentineLayout == true) { 318 if( y & 0x01) { 319 // Odd rows run backwards 320 uint8_t reverseX = (kMatrixWidth - 1) - x; 321 i = (y * kMatrixWidth) + reverseX; 322 } else { 323 // Even rows run forwards 324 i = (y * kMatrixWidth) + x; 325 } 326 } 327 return i; 328 }