Calibrating the Music Box

In order to get an accurate reading, close the music box and run the code below. Then, open your serial monitor. It should output the light level, this is the darkest the box will get so we'll calibrate this value.  

In your code, change the following line:

int dark = 650; -> int dark = your measured value

When you re-run the code, the serial monitor should print "box closed.." when the box is closed. If you wired the backlight to Pin 13, the LCD backlight should also turn off.

/*
* (PROJ03) Metro (and Metro Express!) Music Box
* Desc: 21st century music box: Plays a melody when the box is open.
* Circuit: Piezo, 16x2 LCD, Photo Light Sensor
* 
* by Brent Rubell for Adafruit Industries.   Support Open Source Hardware, buy Adafruit!
* 
*/

// include the lcd library code
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

// Piezo code.
int speakerPin = 5;
int length = 15; // the number of notes
char notes[] = "ccggaagffeeddc "; // a space represents a rest
int beats[] = { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4 };
int tempo = 300;

// Photo Light Sensor Pin
int lightPin = 0;
// Measured Darkness
int dark = 650;

// LCD Backlight Pin
int backlightPin = 13;

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);
  }
}

void playNote(char note, int duration) {
  char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
  int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956 };
  
  // play the tone corresponding to the note name
  for (int i = 0; i < 8; i++) {
    if (names[i] == note) {
      playTone(tones[i], duration);
    }
  }
}

void setup() {
   // set up the serial monitor
   Serial.begin(9600);
   // set up the LCD's cols/rows
   lcd.begin(16, 2);
   // set speaker as an output
   pinMode(speakerPin, OUTPUT);
   // set lcd backlight as an output
   pinMode(backlightPin, OUTPUT);

}

void loop() {
  // read the lightLevel
  int lightLevel = analogRead(lightPin);
  Serial.println("Light Level -> ");
  Serial.println(lightLevel);

  // check lightLevel against dark level (should be set manually by the user, check serial mon.)
  if(lightLevel < dark)
  {
    // Box is OPEN!
    digitalWrite(backlightPin, HIGH);
    lcd.clear();
    Serial.println("Box open, playing music!");
    for (int i = 0; i < length; i++) {
      if(notes[i] == ' ') {
        // rest
        delay(beats[i] * tempo);
        // print a space to indicate a rest
        lcd.print(" ");
      }
      else {
        // play notes in notes[]
        playNote(notes[i], beats [i] * tempo);
        // display current note on the lcd
        lcd.print(notes[i]);
      }
      // pause between notes
      delay(tempo/2);
    }
  }
  else{
    // box is closed
    // turn LCD off
    digitalWrite(backlightPin, LOW);
    lcd.clear();
    lcd.print("box closed...");
    Serial.println("Box closed, don't play music.");  
  }
}

Encountering Problems?

My LCD is not displaying anything.

Check the LCD Wiring guide in CIRC14 to double-check everything is wired correctly. 

My music box is still too sensitive, or it's not sensitive enough.

int dark directly controls how dark or bright the environment inside your music box is. If you find it triggering too easily, decrease its value. 

This guide was first published on Aug 18, 2017. It was last updated on Aug 18, 2017.
This page (Code) was last updated on Oct 22, 2020.