Dawn Dupriest
Published © CC BY-NC-SA

Light-up Musical Ugly Christmas Sweater

This interactive creation takes the traditional sweater up a notch. Hope the pushbutton-activated show helps me win this year's contest.

IntermediateFull instructions provided4 hours1,392
Light-up Musical Ugly Christmas Sweater

Things used in this project

Hardware components

SparkFun LilyPad Arduino SimpleSnap
×1
LilyPad Rainbow LED (strip of 7 colors)
SparkFun LilyPad Rainbow LED (strip of 7 colors)
×1
SparkFun Conductive Thread
×1
SparkFun LilyPad Buzzer
×1
LilyPad Button Board
SparkFun LilyPad Button Board
×1
LilyPad FTDI Basic Breakout - 5V
SparkFun LilyPad FTDI Basic Breakout - 5V
×1
SparkFun USB Mini Cable
×1
LilyPad LED White (5pcs)
SparkFun LilyPad LED White (5pcs)
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

SparkFun Needle Set
Hot glue gun (generic)
Hot glue gun (generic)
Felt
SparkFun Snap Assortment
Sweater

Story

Read more

Schematics

Sweater Wiring using Conductive Thread

Here you can see the inside of the sweater. There is a 10 kOhm resistor sewn between + and A5, under the orange felt. The button connects A5 and GND. It will read a weak HIGH when the button is up, and LOW when the button is down.
I sewed Pin 5 to two LED's closest to the center snowflake. Pin 6 goes to the next two white LED's. Pin 9 goes to the last two white LED's. Pin 10 is sewn to two of the colorful LED's and pin 11 goes to the last two colorful LED's. The + side of the buzzer goes to A2.
The ground thread was complicated to sew, as I had to connect the - side of ALL LED's, the - side of the button, and the - pin on the buzzer together on the same thread. I made a couple of felt bridges so the GND thread didn't cross the other conductive threads. Hot Glue helps keep threads in place so they don't touch.

Code

Ugly Sweater Code

Arduino
This code is based off of this example from the Arduino website, written by David Cuartielles. https://www.arduino.cc/en/Tutorial/PlayMelody I modified it with the notes and beats for Winter Wonderland. I created functionality to let you write a list of which pins are connected to lights, and when the program starts up, it assigns a random light to turn on with each note. If the pushbutton is not pressed, a shooting star animation runs with three successive LED pins lighting up and then getting dimmer, one by one, and then repeating.

In my code, the buzzer is connected to A2, button to A5, and lights on 5, 6, 9, 10, and 11. You can modify this in the code.

You need the FTDI header to program the LilyPad Arduino SimpleSnap. In the "Board" menu, choose LilyPad Arduino.
/* Play Melody
 * -----------
 *
 * Program to play a simple melody
 *
 * Tones are created by quickly pulsing a speaker on and off 
 *   using PWM, to create signature frequencies.
 *
 * Each note has a frequency, created by varying the period of 
 *  vibration, measured in microseconds. We'll use pulse-width
 *  modulation (PWM) to create that vibration.

 * We calculate the pulse-width to be half the period; we pulse 
 *  the speaker HIGH for 'pulse-width' microseconds, then LOW 
 *  for 'pulse-width' microseconds.
 *  This pulsing creates a vibration of the desired frequency.
 *
 * (cleft) 2005 D. Cuartielles for K3
 * Refactoring and comments 2006 clay.shirky@nyu.edu
 * See NOTES in comments at end for possible improvements
 */

 /* Modifications for shooting star animation, Winter Wonderland music, and synchronized random lights
  *  added by Dawn DuPriest 2016
  */

// TONES  ==========================================
// Start by defining the relationship between 
//       note, period, &  frequency. 
int  c4  =   3830;    // 261 Hz 
int  d4  =   3401;     // 294 Hz
int  e4  =   3038;    // 329 Hz 
int  f4  =   2864;    // 349 Hz 
int  g4  =   2550;    // 392 Hz 
int  a4  =   2272;    // 440 Hz 
int  b4  =   2028;    // 493 Hz 
int  C5  =   1912;    // 523 Hz 
// Define a special note, 'R', to represent a rest
int  R  =   0;

// SETUP ============================================
// Set up speaker on a PWM pin (digital 9, 10 or 11)
int speakerOut = A2;
// Do we want debugging on serial out? 1 for yes, 0 for no
int DEBUG = 0;

int etime = 1000;
int oldtime;
int curtime;



// MELODY and TIMING  =======================================
//  melody[] is an array of notes, accompanied by beats[], 
//  which sets each note's relative length (higher #, longer note) 
int melody[] = {  g4,  g4,  g4,  g4,  g4,   e4,  g4,  g4,  g4,  g4, g4, g4,  f4,  g4,  g4,  b4,  b4,  b4, a4, a4, g4, g4, g4, f4, e4, e4, e4, e4, d4, d4, d4, d4, c4, R};
// corresponding array of how long the notes are. 
int beats[]  = { 40, 20, 180,  40,  20,  40, 140, 40, 20, 180, 40, 20, 40, 180,20, 40, 20, 40, 120, 20, 40, 20, 40, 140, 40, 20, 40, 20, 40, 20, 40, 20, 180, 240};

// calculate number of notes in song
int numnotes = sizeof(melody) / sizeof(etime);

int lights[100];  

// you can edit this array to contain the pin numbers of any LED's. The setup code will randomize what light blinks with what note.
int lightpins[] = {5, 6, 9, 10, 11};
int MAX_COUNT = sizeof(melody) / 2; // Melody length, for looping.

// Set overall tempo
long tempo = 8000;
// Set length of pause between notes
int pause = 1000;
// Loop variable to increase Rest length
int rest_count = 100; //<-BLETCHEROUS HACK; See NOTES

// Initialize core variables
int tone_ = 0;
int beat = 0;
long duration  = 0;


// variable for sensor reading
int btn = 0;

int starlight = 0;
int numstarpins = 15;
int fade = 5;

// the first 3 entries in this array are the 3 pins in the shooting star animation. Closest to farthest. 
//The array is filled with dummy entries so you get a delay after the shooting star
// must be PWM pins
int starlightpins[] = { 5, 6, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// Animation starts with the first LED pair and then goes from there.
int brightnesses [] = { 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};


void setup() { 
  pinMode(speakerOut, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);

  oldtime = millis();
  curtime = millis();
  randomSeed(analogRead(A4));
  long prevr;
  long r = 6;
  for(int j = 0; j < numnotes; j++)
  {
    prevr = r;
    r = random(0,5);
    while(r == prevr)
    {
        r = random(0,5);
    }
    lights[j] = lightpins[r];
  }
  lights[numnotes - 1] = 4;
  
}

// PLAY TONE  ==============================================
// Pulse the speaker to play a tone for a particular duration
void playTone() {
  long elapsed_time = 0;
  if (tone_ > 0) { // if this isn't a Rest beat, while the tone has 
    //  played less long than 'duration', pulse speaker HIGH and LOW
    while (elapsed_time < duration) {

      digitalWrite(speakerOut,HIGH);
      delayMicroseconds(tone_ / 2);

      // DOWN
      digitalWrite(speakerOut, LOW);
      delayMicroseconds(tone_ / 2);

      // Keep track of how long we pulsed
      elapsed_time += (tone_);
    } 
  }
  else { // Rest beat; loop times delay
    for (int j = 0; j < rest_count; j++) { // See NOTE on rest_count
      delayMicroseconds(duration);  
    }                                
  }                                 
}

// LET THE WILD RUMPUS BEGIN =============================
void loop() {
  // read signal from button
  btn = digitalRead(A5);
  // if button is down then play music
  if(btn == LOW)
  {
  
  
    for (int i=0; i<MAX_COUNT; i++) {
      tone_ = melody[i];
      beat = beats[i];
  
      duration = beat * tempo; // Set up timing
      if(lights[i] != 4)
      {
        digitalWrite(lights[i],HIGH);
      }
      playTone(); 
      if(lights[i] != 4)
      {
        digitalWrite(lights[i],LOW);
      }
      // A pause between notes...
      delayMicroseconds(pause);

    
    }

    brightnesses[0] = 255;
    for(int i = 1; i < numstarpins; i++)
    {
      brightnesses[i] = 0;
    }

  }
  else // if button is up then do shooting stars.
  {
      
      for(int i = 0; i < numstarpins; i++)
      {
        if(starlightpins[i] == 5 || starlightpins[i] == 6 || starlightpins[i] == 9)
        {
          analogWrite(starlightpins[i],brightnesses[i]);
        }
        if(brightnesses[i] >= fade)
        {
          brightnesses[i] = brightnesses[i] -  fade;
        }
        int nexti = (i+1) % numstarpins;
        if(brightnesses[i] < 128 && brightnesses[i] > 0 &&  brightnesses[nexti] <= 0)
        {
          brightnesses[nexti] = 255;
        }
        
      }// end for
      
  
      delay(10);
  }
  
}

Credits

Dawn Dupriest

Dawn Dupriest

4 projects • 5 followers
Middle School Computer Science teacher, Feminist, Maker. 2012 Poudre School District Teacher of the Year. 2016 Allen Distinguished Educator.

Comments