Pressure-activated Sound Player

by alch_emist in Circuits > Arduino

220 Views, 0 Favorites, 0 Comments

Pressure-activated Sound Player

Sound player prototype
IMG-6003.jpg
IMG-5986.jpg

A mini sound player that lights up and plays a melody when pressure is applied to a force-sensitive resistor. This project incorporates these topics:

  1. Use a force-sensitive resistor to activate code based on the amount of pressure applied as well as vary the output of a piezo buzzer.
  2. Use a potentiometer to change increase or decrease values by turning the dial.
  3. Synchronize LEDs with the sound from a piezo buzzer.
  4. Use a button to activate/deactivate sections of code.

Made in the physical computing class, ATLS 3300, at the University of Colorado, Boulder ATLAS Institute.

Supplies

  • Arduino or any microcontroller of choice with power source
  • Breadboard
  • Jumper cables (I used at least 14)
  • 10k Ohm resistor x1
  • 220 - 3.3k Ohm resistors x2 or more
  • Force sensitive resistor x1
  • Piezo buzzer x1
  • Potentiometer x1
  • LEDs x2 or more
  • Button x1 (optional)

Place the LEDs

image_67205121.JPG

To get started, connect the power bus to the 3.3V pin and the ground bus to the GND pin on the Arduino.

Place your LEDs in succession with each other over the gap in the breadboard, keeping the anode and cathode ends on either the left or right side of the gap. Connect the anode ends of the LEDs to any digital pin on the Arduino - I used pins 11 and 10 for my two LEDs.

Place a 220k - 3.3k ohm on each of the cathode ends of the LEDs, then connect the other end of the resistors to ground.

You can test the LEDs with the code below.

int led1 = 11;// connect Blue LED to pin 11
int led2 = 10;// connect Red LED to pin 10
void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
}

void loop() {
  digitalWrite(led1,HIGH);
  delay(1000);
  digitalWrite(led1,LOW);
  delay(1000);
  digitalWrite(led2,HIGH);
  delay(1000);
  digitalWrite(led2,LOW);
  delay(1000);
}<br>

Place the Force-Sensitive Resistor

fsr.jpg
fsr reading neutral.JPG
fsr reading squeezed.JPG

Courtesy of this source for the information and schematic placement.

Place the force-sensitive resistor on the board facing upwards so that it is secured. Connect the 3.3V power source to one end of the FSR, then connect one end of the 10K ohm resistor to the other end of the FSR. Leave room next to this latter end of the resistor and connect it to an analog input pin on the Arduino - I used pin 0. Finally connect the other end of the resistor to ground.

In the loop of the code, read in the FSR using analogRead() and print this reading to the Serial output. If the FSR is connected correctly, you should be able to see outputs near 0 for its neutral state. If you apply pressure to the FSR by squeezing it slightly, the reading should jump to values above 100.

int led1 = 11;
int led2 = 10;
int fsr = 0; // connect FSR to analog pin 0

void setup(){
Serial.begin(9600);
pinMode(led1,OUTPUT);
pinMode(led2,OUTPUT);
}

void loop(){
int fsrReading = analogRead(fsr);
Serial.print("FSR reading: ");
Serial.println("fsrReading");
}

Place Piezo Buzzer

piezo.jpg

Schematic placement courtesy of this source.

Place the piezo buzzer with one end connected to a digital output pin on the Arduino - I used pin 12 - and the other end connected to ground. Ensure that no other parts are connected along the same rungs as the buzzer.

To allow the buzzer to play music, copy and paste the note pitch definitions from this source into your code. I then made an array containing all these notes called allnotes[] for easy access. I wanted the buzzer to play a segment of William Tell Overture, so I made another array called genMelody[] containing the indices of all the notes in the melody (42 in total). I also made an array to store the durations of these notes called noteDurations[], which contains "8" for "eighth notes", "4" for "quarter notes", and "2" for "half notes".

I then created a function called playMelody() that uses a for-loop to play the individual notes with their corresponding durations. I referenced this code directly from this source for the note duration logic.

Put the playMelody() function in setup() to test the buzzer's output once upon setup.

int allnotes[] = {
  NOTE_B0, NOTE_C1, NOTE_CS1, NOTE_D1, NOTE_DS1, NOTE_E1, NOTE_F1, NOTE_FS1, NOTE_G1, NOTE_GS1, NOTE_A1, NOTE_AS1,
  NOTE_B1, NOTE_C2, NOTE_CS2, NOTE_D2, NOTE_DS2, NOTE_E2, NOTE_F2, NOTE_FS2, NOTE_G2, NOTE_GS2, NOTE_A2, NOTE_AS2,
  NOTE_B2, NOTE_C3, NOTE_CS3, NOTE_D3, NOTE_DS3, NOTE_E3, NOTE_F3, NOTE_FS3, NOTE_G3, NOTE_GS3, NOTE_A3, NOTE_AS3,
  NOTE_B3, NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4,
  NOTE_B4, NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5,
  NOTE_B5, NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6,
  NOTE_B6, NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7,
  NOTE_B7, NOTE_C8, NOTE_CS8, NOTE_D8, NOTE_DS8
};
int genMelody[] = {
  44, 44, 44, 44, 44, 44, 44, 44, 49, 51, 53,
  44, 44, 44, 44, 44, 49, 53, 53, 51, 48, 44,
  44, 44, 44, 44, 44, 44, 44, 44, 49, 51, 53,
  49, 53, 56, 54, 53, 51, 49, 53, 49
};
int noteDurations[] = {
  8, 8, 4, 8, 8, 4, 8, 8, 4, 4, 4,
  8, 8, 4, 8, 8, 4, 8, 8, 4, 4, 4,
  8, 8, 4, 8, 8, 4, 8, 8, 4, 4, 4,
  8, 8, 2, 8, 8, 8, 4, 4, 4
};<br>
void playMelody(){
for (int note = 0; note < 42; note++) { 
int noteDuration = 1000 / (noteDurations[note]); 
tone(12, allnotes[genMelody[note]], noteDuration); 
int pauseBetweenNotes = noteDuration * 1.30; 
delay(pauseBetweenNotes); 
noTone(12); 
} 
}<br>

Place Potentiometer

potent.jpg
potent output.JPG

Place the potentiometer on the board, ensuring that nothing else is connected to the same rungs. Connect the middle end of the potentiometer to an analog input pin on the Arduino - I used pin 1. Then connect one of the outer ends of the potentiometer to 3.3V power, and the other end to ground.

In the code, set the potentiometer as an input, then use analogRead() to read in the values. Print the readings to the Serial output. If the potentiometer is connected correctly, the values outputted should range between 0 - 1023 and change when turning the dial.

Completed Circuit

overall.jpg

Using the Force-Sensitive Resistor to Play Melody

The FSR can be used to start playing the melody as well as vary the duration of each note in the melody.

In the code, first add a condition that if the FSR reading is above 100, play the melody. This will allow the melody to be played only when you administer pressure to the FSR.

Then modify the playMelody() function to take in the FSR reading as a parameter, which can be used to determine the duration of each note: a softer pressure will play the melody slower, while a harder pressure plays it faster.

Normalize the FSR reading to be a decimal number between 1-10 by dividing it by 100, then use this normalized FSR reading as a multiplier for each of the individual note durations.

void playMelody(int fsr){
  float normalizedFsr = fsr/100.0;
  for (int note = 0; note < 42; note++) {
    float noteDuration = 1000 / (noteDurations[note]*normalizedFsr);
    tone(12, allnotes[genMelody[note]], noteDuration);
    float pauseBetweenNotes = noteDuration * 1.30;
    digitalWrite(led, HIGH);
    delay(pauseBetweenNotes/2); //Light an LED while a note is being played
    digitalWrite(led, LOW);
    delay(pauseBetweenNotes/2);
    changeLed();//Change the LED based on desired sequence
    noTone(12);
  }
}<br>

Change the Melody's Pitch With the Potentiometer

The potentiometer can be used to change the pitch of the melody by either raising or lowering all the notes with the dial.

In the code, create a function called changePitch() that will accept the current highest note in the melody and the potentiometer reading. You may have noticed that the potentiometer reading tends to fluctuate frequently, which may lead to the pitch of the notes changing without the user's intention, so I've set up a system based on an idea from this source to help reduce unintentional pitch changes.

I set a mapping for the potentiometer readings to allow for a gap of 500 between each note, and then used the changePitch() function to increment or decrement all the notes in the melody when the potentiometer reading crossed the 500 threshold (meaning that the pitch has changed). I also made the helper function noteVal() to multiply the current index of the note from allnotes by 500 to help the changePitch() function detect the change.

void changePitch(int highnote, int lownote, int potentVal){
  if((highnote < 88) && (potentVal >= noteVal(highnote + 1))){//Ensure that note is within bounds and the potentiometer reading has moved to the next pitch above
    for (int thisNote = 0; thisNote < 42; thisNote++){
      genMelody[thisNote] = genMelody[thisNote] + 1;//Increment all the notes in the melody by one pitch
    }
  }
  else if((lownote > 0) && (potentVal <= noteVal(lownote - 1))){//When the potentiometer moves to the next pitch below
    for (int thisNote = 0; thisNote < 42; thisNote++){
      genMelody[thisNote] = genMelody[thisNote] - 1;//Decrement all the notes in the melody by one pitch
    }
  }
}

int noteVal(int note){
  return 500 * note;//Normalize the note value to the potentiometer threshold of 500 between each note
}<br>

Add a Button to Observe Pitch Fluctuations (Optional)

button.jpg

You may notice that the pitch could possibly vary between tests even if you don't touch the potentiometer. This is because the potentiometer tends to fluctuate between values instead of staying constant. I tried to correct for this in the earlier step by increasing the threshold for changing pitch, but it's not a complete prevention method.

In this step, I added a button that when pressed, one of the LEDs would turn on every time the pitch changes. This is more of a side feature as a way to observe these pitch fluctuations and thus is optional to implement.

Place the button over the gap in the breadboard horizontally so that the two prongs on each side of the button share a side of the breadboard. Connect the bottom right prong to a digital output on the Arduino - I used pin 9. Then connect 3.3V power to the top left prong, a 220 - 3.3K ohm resistor to the bottom left prong, and the other end of the resistor to ground.

In the code, add conditional statements inside each case of the changePitch() function to turn the LED on/off every time the pitch changes. Remember to turn off the LED by calling digitalWrite(led, LOW) right after the changePitch() function is called.

Light Up LEDs With the Melody

image_50408705.JPG

To finish off, you can light up the LEDs when a note is played for the duration of that note.

In the playMelody() function, add the code for turning an LED on and off with a delay equal to half of the total pause time between notes. Use the helper function changeLed() to modify the sequence of the LEDs that turn on using a global variable. I only had two LEDs to work with but you can add more to the sequence here.

Download full code below.

Mini Present Enclosure

image_50416641.JPG
Mini Present Sound Player

I organized my circuit using solid wires on the breadboard so I could fit it into a small 3.5 x 2.5 x 1.25 inch box. I thought the box resembled a small present so I decorated it to look like one by wrapping yellow paper around it, cutting holes for the LEDs and the potentiometer, and placing a pom-pom over the area of the force-sensitive resistor. I also changed the song to play Happy Birthday when the little red pom-pom was pressed.

Code on Github Gist and below: