NEON FLEX LED SIGN
These Neon Flex (LED) Signs are a great way to take your projects to that next level. We go over Design, Cutting it out, Programing, and more. So if you are intrested in making one check out this 2 Part Series on how you can make a Neon Flex Sign of your own.
Part 1
To get started we go over Materials needed, Design, and the CAD & CAM.
Part 2
In this video we get everything wired up and we take a look at the code.
AFFILIATE LINKS TO MATERIALS USED
WIRING DIAGRAM
ARDUINO CODE:
//GET OUR LIBRARIES
#include <FastLED.h>
#include <OneButton.h>
//DEFINE OUR WHAT IS CONNECTED TO OUR PINES
#define LED_PIN_CENTER 4 //CENTER
#define LED_PIN_A 2 //SIDE A
#define LED_PIN_B 7 //SIDE B
#define BTN_PIN 14 //BUTTON
//DEFINE HOW MANY LEDS EACH STRIP HAS
#define NUM_LEDS_CENTER 139 //NUMBER LEDS CENTER
#define NUM_LEDS_SIDE_A 56 //NUMBER LEDS SIDE
#define NUM_LEDS_SIDE_B 56 //NUMBER LEDS SIDE
//DEFINE SETTINGS FOR SUB LOOPS
#define COOLING 55
#define SPARKING 120
// Define the array of leds, This is what we will use to turn on a specific strand of LEDs
CRGB ledsC[NUM_LEDS_CENTER];
CRGB ledsA[NUM_LEDS_SIDE_A];
CRGB ledsB[NUM_LEDS_SIDE_B];
//Global Variables that can be used in any function
unsigned long interval=25; // the time we need to wait
unsigned long previousMillis=0; // millis() returns an unsigned long.
unsigned long interval_b = 100; // the time we need to wait Part 2
uint8_t patternCounter = 0;
uint8_t minBright = 20;
uint8_t maxBright = 80;
bool gReverseDirection = false;
//MORE GLOBAL VARIABLES FOR SUB LOOPS
int numColors = 1;
int ra = 60;
int rb = 0;
int dir = 0;
int dirb = 0;
int dirc = 0;
int la = 0;
int sat = 0;
// Push button connected between pin 14 and GND (no resistor required) Defining our Push Button
OneButton btn = OneButton(BTN_PIN, true, true);
void setup() {
//Initializing our LEDs
FastLED.addLeds<WS2812, LED_PIN_CENTER, GRB>(ledsC, NUM_LEDS_CENTER);
FastLED.addLeds<WS2812, LED_PIN_A, GRB>(ledsA, NUM_LEDS_SIDE_A);
FastLED.addLeds<WS2812, LED_PIN_B, GRB>(ledsB, NUM_LEDS_SIDE_B);
//Set our inital LED Brightness
FastLED.setBrightness(50);
//Serial.begin(9600);
//One Button lets us tell the program what to do when the button is clicked, so it will Run - nextPattern
btn.attachClick(nextPattern);
//This gives us time will testing to upload a new sketch to the board in case it gets stuck, Can take this out once code is finalized
delay(5000);
}
//MAIN LOOP
void loop() {
//SWITCH & CASE - controls the flow of programs by allowing programmers to specify different code that should be executed in various conditions
//BREAK - keyword exits the switch statement, and is typically used at the end of each case. Without a break statement, the switch statement will
//continue executing the following expressions ("falling-through") until a break, or the end of the switch statement is reached.
switch (patternCounter) {
case 0:
solidColor();
break;
case 1:
rainbowBeat();
break;
case 2:
redAlertB();
break;
case 3:
fire();
break;
case 4:
juggle();
break;
case 5:
movingDots();
break;
case 6:
redAlert();
break;
case 7:
redgold();
break;
case 8:
gradientChangeSlow();
break;
case 9:
gradientChangeFast();
break;
}
//NOTICE FastLED.show is here, and not in our Sub Loops
FastLED.show();
btn.tick();
}
void nextPattern() {
//This changes what Case we are on
patternCounter = (patternCounter + 1) % 10; // Change the number after the % to the number of patterns you have
FastLED.clear (); //Clears our current LEDs
}
//------- Put your patterns below -------//
void solidColor() {
//TO Change the Speed Change the 5000
float breath = (exp(sin(millis()/5000.0*PI)) - 0.36787944)*108.0;
//Map Breath Value from above to 0-255, then get the GLOBAL minBright & maxBright Variable
breath = map(breath, 0, 255, minBright, maxBright);
FastLED.setBrightness(breath);
fill_solid(ledsC, NUM_LEDS_CENTER, CRGB::SlateGray);
fill_solid(ledsA, NUM_LEDS_SIDE_A, CRGB::Gold);
fill_solid(ledsB, NUM_LEDS_SIDE_B, CRGB::Gold);
}
void rainbowBeat() {
uint16_t beatA = beatsin16(30, 0, 255);
uint16_t beatB = beatsin16(20, 0, 255);
fill_rainbow(ledsC, NUM_LEDS_CENTER, (beatA+beatB)/2, 8); // Initial Hue - Delta HUE - How fast to advance the led
fill_rainbow(ledsA, NUM_LEDS_SIDE_A, (beatA+beatB)/2, 8);
fill_rainbow(ledsB, NUM_LEDS_SIDE_B, (beatA+beatB)/2, 8);
}
void redAlertB() {
unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - previousMillis) >= interval) {
//LEFT SIDE OF CENTER
ledsC[ra] = CRGB(255,0,0);
if (dir == 0){
ra ++;
if (ra == 140){
dir = 1;
}
}
else if (dir == 1){
ra --;
if (ra == 60){
dir = 0;
}
}
//RIGHT SIDE OF CENTER
ledsC[rb] = CRGB(255,0,0);
if (dirb == 0){
rb ++;
if (rb == 60){
dirb = 1;
}
}
else if (dirb == 1){
rb --;
if (rb == 0){
dirb = 0;
}
}
ledsA[la] = CRGB(255,0,0);
ledsB[la] = CRGB(255,0,0);
if (dirc == 0){
la ++;
if (la == NUM_LEDS_SIDE_A){
dirc = 1;
}
}
else if (dirc == 1){
la --;
if (la == 0){
dirc = 0;
}
}
fadeToBlackBy(ledsC, NUM_LEDS_CENTER, 8);
fadeToBlackBy(ledsA, NUM_LEDS_SIDE_A, 15);
fadeToBlackBy(ledsB, NUM_LEDS_SIDE_B, 15);
previousMillis = millis();
}
}
void fire() {
// Array of temperature readings at each simulation cell
static byte heat[NUM_LEDS_CENTER];
// Step 1. Cool down every cell a little
for( int i = 0; i < NUM_LEDS_CENTER; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS_CENTER) + 2));
}
for( int i = 0; i < NUM_LEDS_SIDE_A; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS_SIDE_A) + 2));
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for( int k= NUM_LEDS_CENTER - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
}
for( int k= NUM_LEDS_SIDE_A - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if( random8() < SPARKING ) {
int y = random8(7);
heat[y] = qadd8( heat[y], random8(160,255) );
}
// Step 4. Map from heat cells to LED colors
for( int j = 0; j < NUM_LEDS_CENTER; j++) {
CRGB color = HeatColor( heat[j]);
int pixelnumber;
if( gReverseDirection ) {
pixelnumber = (NUM_LEDS_CENTER-1) - j;
} else {
pixelnumber = j;
}
ledsC[pixelnumber] = color;
}
// Step 4. SIDE A
for( int j = 0; j < NUM_LEDS_SIDE_A; j++) {
CRGB color = HeatColor( heat[j]);
int pixelnumber;
if( gReverseDirection ) {
pixelnumber = (NUM_LEDS_SIDE_A-1) - j;
} else {
pixelnumber = j;
}
ledsA[pixelnumber] = color;
}
// Step 4. SIDE B
for( int j = 0; j < NUM_LEDS_SIDE_B; j++) {
CRGB color = HeatColor( heat[j]);
int pixelnumber;
if( gReverseDirection ) {
pixelnumber = (NUM_LEDS_SIDE_B-1) - j;
} else {
pixelnumber = j;
}
ledsB[pixelnumber] = color;
}
}
void juggle() {
fadeToBlackBy( ledsC, NUM_LEDS_CENTER, 20);
fadeToBlackBy( ledsA, NUM_LEDS_SIDE_A, 20);
fadeToBlackBy( ledsB, NUM_LEDS_SIDE_B, 20);
uint8_t dothue = 0;
for( int i = 0; i < 8; i++) {
ledsC[beatsin16( i+7, 0, NUM_LEDS_CENTER-1 )] |= CHSV(dothue, 200, 255);
ledsA[beatsin16( i+7, 0, NUM_LEDS_SIDE_A-1 )] |= CHSV(dothue, 200, 255);
ledsB[beatsin16( i+7, 0, NUM_LEDS_SIDE_B-1 )] |= CHSV(dothue, 200, 255);
dothue += 32;
}
}
void movingDots() {
// beatsin16( BPM, uint16_t low, uint16_t high) returns a 16-bit value
// that rises and falls in a sine wave, 'BPM' times per
// minute, between the values of 'low' and 'high'.
//CENTER
uint16_t posBeat = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 0);
uint16_t posBeat2 = beatsin16(60, 0, NUM_LEDS_CENTER - 1, 0, 0);
uint16_t posBeat3 = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 32767);
uint16_t posBeat4 = beatsin16(60, 0, NUM_LEDS_CENTER - 1, 0, 32767);
//SIDES A & B
uint16_t posBeat5 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 0);
uint16_t posBeat6 = beatsin16(60, 0, NUM_LEDS_SIDE_B - 1, 0, 0);
uint16_t posBeat7 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 32767);
uint16_t posBeat8 = beatsin16(60, 0, NUM_LEDS_SIDE_B - 1, 0, 32767);
// Wave for LED color
uint8_t colBeat = beatsin8(45, 0, 255, 0, 0);
//HUE SATURATION VALUE (Brightness)
ledsC[(posBeat + posBeat2) / 2] = CHSV(colBeat, 255, 255);
ledsC[(posBeat3 + posBeat4) / 2] = CHSV(colBeat, 255, 255);
ledsA[(posBeat5 + posBeat6) / 2] = CHSV(colBeat, 255, 255);
ledsA[(posBeat7 + posBeat8) / 2] = CHSV(colBeat, 255, 255);
ledsB[(posBeat5 + posBeat6) / 2] = CHSV(colBeat, 255, 255);
ledsB[(posBeat7 + posBeat8) / 2] = CHSV(colBeat, 255, 255);
//Turn Off Lights by fadeing
fadeToBlackBy(ledsC, NUM_LEDS_CENTER, 10);
fadeToBlackBy(ledsA, NUM_LEDS_SIDE_A, 10);
fadeToBlackBy(ledsB, NUM_LEDS_SIDE_B, 10);
}
void redAlert() {
FastLED.setBrightness(50);
//(BEATS per min, FIRST LED, LAST LED, TIMEBASE, PHASE OFFSET)
//beatsin16 generates a 16-bit sine wave at a given BPM, that oscillates within a given range
//So we are generating this SinWave between 60 & 139 on our LED Strip for the Center part
uint16_t sinBeatA = beatsin16(15, 60, 139, 0, 21845);
uint8_t sinBeatAA = beatsin8(15, 60, 139, 0, 0);
uint16_t sinBeatB = beatsin16(30, 0, 60, 0, 21845);
uint8_t sinBeatBB = beatsin8(15, 0, 60, 0, 0);
uint16_t sinBeatL = beatsin16(15, 0, 28, 0, 21845);
uint8_t sinBeatLL = beatsin8(15, 0, 28, 0, 0);
uint16_t sinBeatM = beatsin16(15, 28, 56, 0, 21845);
uint8_t sinBeatMM = beatsin8(15, 28, 56, 0, 0);
ledsC[sinBeatA] = CRGB(255,0,0);
ledsC[sinBeatB] = CRGB(255,0,0);
ledsC[sinBeatAA] = CRGB(255,0,0);
ledsC[sinBeatBB] = CRGB(255,0,0);
ledsA[sinBeatL] = CRGB(255,0,0);
ledsA[sinBeatLL] = CRGB(255,0,0);
ledsA[sinBeatM] = CRGB(255,0,0);
ledsA[sinBeatMM] = CRGB(255,0,0);
ledsB[sinBeatL] = CRGB(255,0,0);
ledsB[sinBeatLL] = CRGB(255,0,0);
ledsB[sinBeatM] = CRGB(255,0,0);
ledsB[sinBeatMM] = CRGB(255,0,0);
fadeToBlackBy(ledsC, NUM_LEDS_CENTER, 5);
fadeToBlackBy(ledsA, NUM_LEDS_CENTER, 10);
fadeToBlackBy(ledsB, NUM_LEDS_CENTER, 10);
}
void redgold() {
uint16_t sinBeat = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 0);
uint16_t sinBeat2 = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 21845);
uint16_t sinBeat3 = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 43690);
uint16_t sinBeat4 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 0);
uint16_t sinBeat5 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 21845);
uint16_t sinBeat6 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 43690);
ledsC[sinBeat] = CRGB::Red;
ledsC[sinBeat2] = CRGB::DarkRed;
ledsC[sinBeat3] = CRGB::Maroon;
ledsA[sinBeat4] = CRGB::DarkGoldenrod;
ledsA[sinBeat5] = CRGB::Goldenrod;
ledsA[sinBeat6] = CRGB::Gold;
ledsB[sinBeat4] = CRGB::DarkGoldenrod;
ledsB[sinBeat5] = CRGB::Goldenrod;
ledsB[sinBeat6] = CRGB::Gold;
fadeToBlackBy(ledsC, NUM_LEDS_CENTER, 6);
fadeToBlackBy(ledsA, NUM_LEDS_SIDE_A, 6);
fadeToBlackBy(ledsB, NUM_LEDS_SIDE_A, 6);
}
void gradientChangeSlow() {
uint8_t starthue_c = beatsin8(4, 0, 255);
uint8_t endhue_c = beatsin8(8, 255, 255);
uint8_t starthue_ab = beatsin8(2, 0, 255);
uint8_t endhue_ab = beatsin8(4, 255, 255);
unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - previousMillis) >= interval_b) {
fill_gradient(ledsC,NUM_LEDS_CENTER,CHSV(starthue_c, 255, 255),CHSV(endhue_c, starthue_c, 255),FORWARD_HUES);
fill_gradient(ledsA,NUM_LEDS_SIDE_A,CHSV(starthue_ab, 255, 255),CHSV(endhue_ab, starthue_ab, 255),FORWARD_HUES);
fill_gradient(ledsB,NUM_LEDS_SIDE_B,CHSV(starthue_ab, 255, 255),CHSV(endhue_ab, starthue_ab, 255),FORWARD_HUES);
}
}
void gradientChangeFast() {
uint8_t starthue_c = beatsin8(32, 0, 255);
uint8_t endhue_c = beatsin8(32, 255, 0);
unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - previousMillis) >= interval_b) {
fill_gradient(ledsC,NUM_LEDS_CENTER,CHSV(starthue_c, 255, 255),CHSV(endhue_c, starthue_c, 255),FORWARD_HUES);
fill_gradient(ledsA,NUM_LEDS_SIDE_A,CHSV(starthue_c, 255, 255),CHSV(endhue_c, starthue_c, 255),FORWARD_HUES);
fill_gradient(ledsB,NUM_LEDS_SIDE_B,CHSV(starthue_c, 255, 255),CHSV(endhue_c, starthue_c, 255),FORWARD_HUES);
}
}