Things used in this project

Parts & Materials:
Attiny85
Atmel ATTiny85
×1
Omron b3f 1000 image 75px
Tactile Button Switch (6mm) Single
×1
Mfr 25fbf52 47r5 sml
Resistor 47.5 ohm
×1
Adafruit industries ada654 image 75px
Coin Cell Battery CR2032
×1
CR2032 Coin Cell Battery Holder
×1
17mm Piezo Buzzer
×1
5mm Oval LED - Red
×1
5mm Oval LED - Blue
×1
5mm Oval LED - Green
×1
Osh park
OSH Park Custom fabricated PCB
×1
Software apps and online services:
Ide web
Arduino IDE
Eagle PCB Design
Autodesk AutoCAD
Hand tools and fabrication machines:
Full Spectrum Hobby Laser
09507 01
Soldering iron (generic)
SparkFun AVR Programmer

Custom parts and enclosures

Snowman Laser Cut File
This is the .dwg of the snowman. We cut it on a laser cutter. Note that there are two layers, one that must be cut all the way through, and another that is only engraved (the snowman's face, etc).
oN5o8mghQkQ9jeMFaAgX.dwg
Eagle and Gerber files
These are the files you need to order the PCB. I have used Osh Park in the past, this time we went with PCBWay to get a better price on a large number of boards, as well as the option of white boards.
Gkz6ghuw2nn1Pp6PMCB3.zip

Schematics

Fritzing File
If you'd prefer not to order a PCB, you could also just assemble the circuit on a perfboard using this diagram.
8JGzJ8tZQKCrbKjHYufO.fzz

Code

Arduino Code for the ATTinyArduino
This is the code for the ornament. To program the ATTiny, you will need a programmer (I used this one https://www.sparkfun.com/products/9825) and you will need to set up your Arduino IDE to do it (there is a great guide here http://highlowtech.org/?p=1695).
#include <EEPROM.h>
#include <avr/sleep.h>

int ledBlu = 0;
int ledGrn = 1;
int ledRed = 2;
int speakerPin = A2;

int switcher = 0;

//number of notes in song
int length = 117;
//notes
char notes[] = "gefgCbCDCbagbCDCbaagCegagfefggefgCbCDCbagbCDCbaagCegagfedccaaCCbagefagfeeddggbbDbCDCbaggefgCbCDCbagbCDCbaagCegaggabC ";
//length of each note
int beats[] = { 4,3,1,2,4,1,1,2,2,2,2,6,1,1,2,2,2,1,1,2,2,2,1,1,2,2,2,2,8,4,3,1,2,4,1,1,2,2,2,2,6,1,1,2,2,2,1,1,2,2,2,1,1,2,2,2,2,6, 2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,2,2,2,2,2,2,1,1,2,2,2,2,6 ,4,3,1,2,4,1,1,2,2,2,2,6,1,1,2,2,2,1,1,2,2,2,1,1,4,4,4,4,8,8};
//tempo
int tempo = 140;

//shuts down unneeded functions to save battery when not in use - acts as a mode
void sleepNow()
{
  DDRB  = B000000;
  PORTB = B100000;
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();
  sleep_disable();
}

//reference pointer used to keep track of what mode we are in - stored in eeprom
typedef void(*ModePtr)();
ModePtr ModePtrs[] =
{
  sleepNow,
  playFrosty
};

//number of modes, initialize mode
const static byte mode_count = sizeof(ModePtrs) / sizeof(ModePtrs[0]);
static byte mode = 0;

//function to play a tone at a set frequency for a given duration
void playTone(int tone, int duration)
{
  for (long i = 0; i < duration * 1000L; i += tone * 2)
  {
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(tone);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(tone);
  }
}

//function to play a note for a duration - calls playTone
void playNote(char note, int duration)
{
  //these two arrays allow us to get the frequency associated with a letter (note)
  char names[] = { 'c', 'd', 'e', 'f', 's', 'g', 'a', 'v', 'b', 'C', 'D', 'E' , 'F'};
  int tones[] = { 1915, 1700, 1519, 1432, 1352, 1275, 1136, 1073, 1014, 956, 852, 758, 730};

  //calls playTone to play the tone
  for (int i = 0; i < 13; i++)
  {
    if (names[i] == note)
    {
      playTone(tones[i], duration);
    }
  }
}

//function to blink the lights and play the song - acts as a mode
void playFrosty()
{
  for (int i = 0; i < length; i++)
  {
    //rests
    if (notes[i] == ' ')
    {
      delay(beats[i] * tempo); // rest
    }
    //notes
    else
    {
      playNote(notes[i], beats[i] * tempo);
    }

    //randomly lights up one LED in time with the music
    switcher = random(0,3);
    if (switcher == 0)
    {
      digitalWrite(ledBlu, LOW);
      digitalWrite(ledGrn, HIGH);
      digitalWrite(ledRed, LOW);
    }
    if (switcher == 1)
    {
      digitalWrite(ledBlu, LOW);
      digitalWrite(ledGrn, LOW);
      digitalWrite(ledRed, HIGH);
    }
    if (switcher == 2)
    {
      digitalWrite(ledBlu, HIGH);
      digitalWrite(ledGrn, LOW);
      digitalWrite(ledRed, LOW);
    }

    // pause between notes
    delay(tempo / 2);
  }
}

void setup()
{
  //pinmodes
  pinMode(ledBlu, OUTPUT);
  pinMode(ledGrn, OUTPUT);
  pinMode(ledRed, OUTPUT);
  pinMode(speakerPin, OUTPUT);

  //eeprom and sleep setup
  ADCSRA &= ~(1<<ADEN);
  //if reset button is pressed...
  if (bit_is_set(MCUSR, EXTRF))
  {
    mode = EEPROM.read(1) % mode_count; //get current mode from eeprom
    EEPROM.write(1, (mode + 1) % mode_count); //store the next mode into eeprom
  }
  else
  {
    mode = 0;
    EEPROM.write(1, 1);
  }
}

void loop()
{
  //all the loop does is run the correct function depending on the current mode
  ModePtrs[mode]();
}

Credits

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Add projectSign up / Login
Community Projects Magazine Maker Faire Shop Share
Respect project