Programmable RGB LED Strip with Microphone

Every year at christmas time all neighbors put their LED strips out and make their houses glowing as if there no tomorrow. Last year they got me and I wanted to put an LED strip on my balcony as well. But not a simple one! I wanted a programmable RGB LED strip with a microphone to get some sound-2-light effects.

Programmable RGB Led strip

Programmable RGB Led strip

Click here for a video of the strip in action – only blue color for testing purposes. Here is another Video running some patterns at night time.

Building the strip was very simple. At first I bought the following compnents:

  • Addressable RGB LED Strip (I got this cheap WS2811 from china but you can use any other) (~ 10 EUR)
Addressable LED Strip

Addressable LED Strip

 

Arduino Nano v3.0

Arduino Nano v3.0

  • Sound module (a complete one or you build one yourself) ( ~ 2.00 EUR )
Sound module

Sound module

  •  5V Power Supply (The whole configuration uses up to 1 Amp but I bought a supply with 4 Amps to be able to extend the LED strip with more lights later on) ( ~ 5 EUR)
Power Supply

Power Supply

  • Cable distribution box (~ 0.5 EUR)
Cable distribution box

Cable distribution box

Before putting everything together I developed a prototype on a breadboard. The circuit layout looks like this:

Circuit Layout

Circuit Layout

The Arduino can be programmed via USB using ArduinoIDE. I used the FastLED library to rite patterns for the LED strip. Here is my source code:

#include 
#define NUM_LEDS 50 // number of LEDS on the strip
#define DATA_PIN 3  // connection to the strip
#define MIC_PIN A3  // input for the microphone

// init led array
CRGB leds[NUM_LEDS];

// SETUP

void setup() {
  // set mic pin to input
  pinMode(MIC_PIN, INPUT);
  // init serial line for debugging
  Serial.begin(9600);
  // set WS2811 led strip
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
}


// HELPER FUNCTIONS

// all LEDS same color
void colorAll(CRGB color) {
  for (int i=0;i<NUM_LEDS;i++) leds[i] = color; FastLED.show(); } // dims a color to percent CRGB colorPercent(CRGB color, int percent) { if (percent > 100) percent = 100;
  if (percent < 0) percent = 0; return(CRGB(color.r * percent / 100, color.g * percent / 100, color.b * percent / 100)); } // random color CRGB randomColor() { return(CRGB(random8(), random8(), random8())); } // PATTERNS // Let snow flake fill the strip. void snowFlake(int wait_ms=50) { for (int pos = NUM_LEDS; pos >= 0; pos--) {
    for (int i = 0; i < pos; i++) {
      leds[i-1] = CRGB::Black;
      leds[i] = CRGB::White;
      FastLED.show();
      delay(wait_ms);
    }
  }
}

// random led colors
void randomFill(int iterations = 200, int wait_ms = 50) {
  while (iterations) {
    for (int i = 0; i < NUM_LEDS; i++) {
      leds[i] = randomColor();
    }
    FastLED.show();
    delay(wait_ms);
    iterations--;
  }
}

// random pixels
void randomPixel(int iterations = 5, int wait_ms = 500) {
  // let leds randomly glow
  while (iterations) {
    colorAll(CRGB::Black);
    for (int k = 0; k < NUM_LEDS/5; k++) {
      leds[random8(NUM_LEDS)] = randomColor();
      FastLED.show();
      delay(wait_ms);
    }
    iterations--;
  }
}

// strobe light
void strobe(int iterations = 10, int flash = 50) {
  // strobe lights
  while (iterations) {
    CRGB color = randomColor();
    for(int j = 0; j < 10; j++) {
      colorAll(color);
      delay(flash);
      colorAll(CRGB::Black);
      delay(flash);
    }
    delay(1000);
    iterations--;
  }
}

// fades a color in and out
void fadeInOut(int iterations = 5, int wait_ms = 10) {
  while (iterations) {
    CRGB color = randomColor();
    for (int percent = 0; percent <= 100; percent++) { colorAll(colorPercent(color, percent)); delay(wait_ms); } for (int percent = 100; percent >= 0; percent--) {
      colorAll(colorPercent(color, percent));
      delay(wait_ms);
    }
    iterations--;
  }  
}

// Generate rainbow colors across 0-255 positions.
CRGB wheelColor(int pos) {
  if (pos < 85) return(CRGB(pos * 3, 255 - pos * 3, 0));
  if (pos < 170) {
    pos -= 85;
    return(CRGB(255 - pos * 3, 0, pos * 3));
  }
  pos -= 170;
  return(CRGB(0, pos * 3, 255 - pos * 3));
}

// rainbow colors
void rainbow(int iterations = 3, int wait_ms = 20) {
  while (iterations) {
    for (int j = 0; j < 256; j++) {
      for (int i = 0; i < NUM_LEDS; i++) leds[i] = wheelColor((i+j) & 255);
      FastLED.show();
      delay(wait_ms);
    }
    iterations --;
  }
}

// knight rider animation
void knightRider(int iterations = 5, int wait_ms = 50) {
  while (iterations) {
    for (int i = 0; i < NUM_LEDS; i++) {
      leds[i] = CRGB::Red;
      for (int p = 1; p <= 5; p++) {
        if (i-p < 0) continue; leds[i-p] = leds[i].nscale8(250-(p*50)); } FastLED.show(); delay(wait_ms); } for (int i = NUM_LEDS; i >= 0; i--) {
      leds[i] = CRGB::Red;
      for (int p = 1; p <= 5; p++) { if (i+p > NUM_LEDS) continue;
        leds[i+p] = leds[i].nscale8(250-(p*50));
      }
      FastLED.show();
      delay(wait_ms);
    }
    iterations--;
  }
}

// dips on the stripe
void dip(int iterations = 10, int wait_ms = 50) {
  while (iterations) {
    int pos = random8(NUM_LEDS);
    CRGB color = randomColor();
    for (int i = 0; i <= 10; i++) {
      for (int j = 0; j < i; j++) {
        if ((i+j)*10 <= 100) { leds[pos+j] = colorPercent(color, 100-(i+j)*10); leds[pos-j] = colorPercent(color, 100-(i+j)*10); FastLED.show(); delay(wait_ms); } } } iterations--; } } // moves randomly around and stays void randomStay(int iterations = 10, int wait_ms = 200) { int oldpos = 0; while (iterations) { CRGB color = randomColor(); int pos = random(NUM_LEDS); if (pos > oldpos) {
      for (int i = oldpos+1; i < pos+1; i++) { leds[i-1] = CRGB::Black; leds[i] = color; FastLED.show(); delay(wait_ms * abs(pos-i)/NUM_LEDS); } } else { for (int i = oldpos-1; i > pos-1; i--) {
        leds[i+1] = CRGB::Black;
        leds[i] = color;
        FastLED.show();
        delay(wait_ms * abs(pos-i)/NUM_LEDS);
      }
    }
    oldpos = pos;
    delay(1000);
    iterations--;
  }
}

// simulates fireflys
void fireflys(int iterations = 200, int wait_ms = 100, int fly_count = 5) {
  int flys[fly_count];  
  for (int i = 0; i < fly_count; i++) flys[i] = random8(NUM_LEDS);

  while (iterations) {
    for (int f = 0; f < fly_count; f++) {
      int direction = random8(3);
      int pos = flys[f];
      if (direction < 1 && pos > 0) {
        leds[pos] = CRGB::Black;
        pos--;
        leds[pos] = CRGB::Yellow;        
      } else if (direction > 1 && pos < NUM_LEDS) {
        leds[pos] = CRGB::Black;
        pos++;
        leds[pos] = CRGB::Yellow;        
      }
      flys[f] = pos;
    }
    FastLED.show();
    delay(wait_ms);
    
    iterations--;
  }
  
}

// Simulates TV turning off
void tvOff(int iterations = 10, int wait_ms = 10) {
  while (iterations) {
    CRGB color = randomColor();
    colorAll(color);
    for (int i = 0; i < NUM_LEDS/2; i++) { leds[i] = CRGB::Black; leds[NUM_LEDS-i] = CRGB::Black; FastLED.show(); delay(wait_ms); } delay(100); for (int percent = 100; percent >= 0; percent--) {
      leds[NUM_LEDS/2-1] = colorPercent(color, percent);
      leds[NUM_LEDS/2] = colorPercent(color, percent);
      leds[NUM_LEDS/2+1] = colorPercent(color, percent);
      leds[NUM_LEDS/2+2] = colorPercent(color, percent);
      FastLED.show();
      delay(wait_ms);
    }
    delay(2000);
    iterations--;
  }
}

// simulates rocket start
void rocket(int iterations = 5) {
  while (iterations) {
    colorAll(CRGB::Black);
    CRGB color = randomColor();
    // fired on
    for (int i = 0; i < 5; i++) { leds[i] = CRGB::Yellow; if (i > 0) leds[i-1] = CRGB::Red;
      if (i > 1) leds[i-2] = CRGB::Black;
      FastLED.show();
      delay(500);
    }
    // start
    for (int i = 5; i < NUM_LEDS; i++) { leds[i] = color; if (i > 9) leds[i-10] = CRGB::Black;
      FastLED.show();
      delay(5);
    }
    // explodes
    for (int i = 0; i < 20; i++) { for (int j = NUM_LEDS-i; j > NUM_LEDS-i-10; j--) {
        leds[j] = colorPercent(randomColor(), 100-(i*5));
        FastLED.show();
        delay(20-i);
      }
      leds[NUM_LEDS-i] = CRGB::Black;
    }
    iterations--;
  }
}

// sound meter
void sound2light() {
  int oldPos = 0;
  while (true) {

    int lastval = 1024;
    for (int runs = 0; runs <= 100; runs++) {
      int val = analogRead(MIC_PIN);
      if (val < lastval) lastval = val; } int pos = map(lastval, 1024, 0, 0, NUM_LEDS); if (oldPos > pos) pos = oldPos-1;
  
  // First, clear the existing led values
  FastLED.clear();
  for(int led = 0; led < pos; led++) { 
    leds[led] = CRGB::Blue; 
  }
  FastLED.show();
  oldPos = pos;

  }
}

// sound lets pixels walk the strip
void sound2pixel() {
  while (true) {

    int lastval = 1024;
    for (int runs = 0; runs <= 100; runs++) {
      int val = analogRead(MIC_PIN);
      if (val < lastval) lastval = val; } for(int i = NUM_LEDS; i > 0; i--) { 
      leds[i] = leds[i-1];
    }

    if (lastval < 512) leds[0] = CRGB::Blue;
    else leds[0] = CRGB::Black;
    FastLED.show();
  }
}

// MAIN
void loop() {
  rocket();
  tvOff();
  fireflys();
  randomStay();
  dip();
  knightRider();
  rainbow();
  fadeInOut();
  strobe();
  randomPixel();
  randomFill();
  snowFlake();

  // demo
//  sound2light();
//  sound2pixel();
}

When I was sure that everything works properly I put the parts into the cable distribution box and used hot glue to fix it.

Final Circuit in Box

Final Circuit in Box

After everything was in position I closed the box and used isolation tape to protect it from water on the balcony – at least a bit ;-). A separate part of tape was used to secure the USB port. The final box looks like this:

Final box - USB Port open

Final box – USB Port open

Final box - USB Port closed

Final box – USB Port closed

Final box - Microphone output

Final box – Microphone output

 

Leave a Reply

Your email address will not be published. Required fields are marked *