Skip to main content

Arduinos: Piezo Software

Physical Computing, the Internet of Things, Sensors and Servos

Detect Knock, Read Serial Monitor, and Calibrate

You will first declare your variables. You can give them any names you want that will make sense to you. They should always begin with a lowercase letter.

knockSensor=A0 is the analog pin to which your piezo connects.

threshold=100 is a rough guess on a scale of 0-1023 to get us started. You will adjust this number based on the sensitivity of your piezo.

sensorReading=0 uses 0 as a placeholder until the function "analogRead" puts data it "reads" from the analog piezo element there.

 

The data type "void" means nothing is expected to return from that function.

The setup() function only runs once when the sketch begins. This is just used to declare things and is one of the two main structures.

The begin() function sets the data rate in bits per second (baud). Standards at https://www.arduino.cc/en/Serial/Begin

Serial is the communication of Receiving RX<0 and Transmitting TX>1 of the digital pins of the Arduino with the computer and the period (.) means apply this function to this communication.

 

The loop() function is running continuously and is the second of two main structures.

The analogRead() function is an analog input function that maps the value from the input pin in the parentheses on a scale of 0-5 Volts and uses the on-board 6 channel 10-bit analog to digital converter to return an integer value from 0-1023.

An if()/else conditonal control structure means that if a certain condition declared is met, create some action, else, do something else, in this case, nothing.

The comparison operator >= means greater than or equal to.

The println() function prints data as text/numbers followed by a carriage return to the Serial port which can be read by the monitor.

The delay() function delays the program by value declared in milliseconds, so delay(100) is by 1/10th of a second.

/* Knock Sensor
   This sketch reads a piezo element to detect a knocking sound.
   It reads an analog pin and compares the result to a set threshold.
   If the result is greater than the threshold, it writes
   "knock" to the serial port, and toggles the LED on pin 13.
   The circuit:
    * + connection of the piezo attached to analog in 0
    * - connection of the piezo attached to ground
    * 10kohm resistor attached from analog in 0 to ground
   http://www.arduino.cc/en/Tutorial/Knock
   This example code is in the public domain.
 */
// these constants won't change:
const int knockSensor = A0; // the piezo is connected to analog pin 0
const int threshold = 100;  // threshold value to decide when the detected sound is a knock or not
// these variables will change:
int sensorReading = 0;      // variable to store the value read from the sensor pin
void setup() {
  Serial.begin(9600);       // use the serial port
}
void loop() {
  // read the sensor and store it in the variable sensorReading:
  sensorReading = analogRead(knockSensor);
  // if the sensor reading is greater than the threshold:
  if (sensorReading >= threshold) {
    // send the string "Knock!" back to the computer, followed by new line
    Serial.println("Knock!");
  }
  delay(100);  // delay to avoid overloading the serial port buffer
}

Translate from Notes to Frequency (Hz)

The basic formula for the frequencies of the notes of the equal tempered scale is given by
fn = f0 * (a)n 
where
f0 = the frequency of one fixed note which must be defined. A common choice is setting the A above middle C (A4) at f0 = 440 Hz.
n = the number of half steps away from the fixed note you are. If you are at a higher note, n is positive. If you are on a lower note, n is negative.
fn = the frequency of the note n half steps away.
a = (2)1/12 = the twelth root of 2 = the number which when multiplied by itself 12 times equals 2 = 1.059463094359... 

Examples using A4 = 440 Hz:


C5 = the C an octave above middle C. This is 3 half steps above A4 and so the frequency is 
f3 = 440 * (1.059463..)3 = 523.3 Hz 
If your calculator does not have the ability to raise to powers, then use the fact that
(1.059463..)3 = (1.059463..)*(1.059463..)*(1.059463..)
That is, you multiply it by itself 3 times.

Middle C is 9 half steps below A4 and the frequency is:
f -9 = 440 * (1.059463..)-9 = 261.6 Hz 
If you don't have powers on your calculator, remember that the negative sign on the power means you divide instead of multiply. For this example, you divide by (1.059463..) 9 times. 

http://www.phy.mtu.edu/~suits/NoteFreqCalcs.html

Using a scientific calculator, you have a = (2)1/12, which can be calculated using the x root y function; n is the number of notes away from A4, higher note positive, lower note negative so a to the n power can use the x to the y power function; and f0  we will keep constant at 440 Hz. (For n, you have to include white and black keys.)

Knowing that there are 12 steps per octave, and A4 = 440, what should A3 equal? A5?

Let's calculate A#4 and F#4 together. Then each of you will calculate another on your own.

http://www.phy.mtu.edu/~suits/notefreqs.html

To use numbers the Arduino can use, round to the nearest whole number.

 

Reading Sheet Music

The absolute best guide I've ever seen to reading sheet music. http://www.musicnotes.com/blog/2014/04/11/how-to-read-sheet-music/

We are reading to find which note we need on a scale of C1-C8 including sharps and the duration of the note.

Note Type 1/16 1/8 3/16 1/4 6/16 1/2 3/4 1
Duration for Arduino 16 8 5 4 3 2 2 1

Some example codes:

Hedwig's Theme

// notes in the melody (Hedwig's Theme):
int melody[] = {
  NOTE_B4, NOTE_E4, NOTE_G4, NOTE_FS4, NOTE_E4, NOTE_B4, NOTE_A4, NOTE_FS4,
  NOTE_E4, NOTE_G4, NOTE_FS4, NOTE_DS4, NOTE_F4, NOTE_B3};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int noteDurations[] = {
  4, 3, 12, 4, 2, 4, 2, 2,
  4, 12, 4, 2, 4, 2 };

Mario Main Theme

//Mario main theme melody
int melody[] = {
  NOTE_E7, NOTE_E7,0, NOTE_E7, 
  0, NOTE_C7, NOTE_E7,0,
  NOTE_G7,0,0,0,
  NOTE_G6,0,0,0, 

  NOTE_C7,0,0, NOTE_G6, 
  0,0, NOTE_E6,0, 
  0, NOTE_A6, 0, NOTE_B6, 
  0, NOTE_AS6, NOTE_A6, 0, 

  NOTE_G6, NOTE_E7, NOTE_G7, 
  NOTE_A7, 0, NOTE_F7, NOTE_G7, 
  0, NOTE_E7, 0,NOTE_C7, 
  NOTE_D7, NOTE_B6, 0, 0,

  NOTE_C7, 0, 0, NOTE_G6, 
  0, 0, NOTE_E6, 0, 
  0, NOTE_A6, 0, NOTE_B6, 
  0, NOTE_AS6, NOTE_A6, 0, 

  NOTE_G6, NOTE_E7, NOTE_G7, 
  NOTE_A7, 0, NOTE_F7, NOTE_G7, 
  0, NOTE_E7, 0,NOTE_C7, 
  NOTE_D7, NOTE_B6, 0, 0};
  
//Mario main theme tempo
int noteDurations[] = {
  12, 12, 12, 12, 
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12, 

  12, 12, 12, 12,
  12, 12, 12, 12, 
  12, 12, 12, 12, 
  12, 12, 12, 12, 

  9, 9, 9,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,

  9, 9, 9,
  12, 12, 12, 12,
  12, 12, 12, 12,
  12, 12, 12, 12,
};

Mario Underworld

int melody[] = {
  NOTE_C4, NOTE_C5, NOTE_A3, NOTE_A4, 
  NOTE_AS3, NOTE_AS4, 0,
  0,
  NOTE_C4, NOTE_C5, NOTE_A3, NOTE_A4, 
  NOTE_AS3, NOTE_AS4, 0,
  0,
  NOTE_F3, NOTE_F4, NOTE_D3, NOTE_D4,
  NOTE_DS3, NOTE_DS4, 0,
  0,
  NOTE_F3, NOTE_F4, NOTE_D3, NOTE_D4,
  NOTE_DS3, NOTE_DS4, 0,
  0, NOTE_DS4, NOTE_CS4, NOTE_D4,
  NOTE_CS4, NOTE_DS4, 
  NOTE_DS4, NOTE_GS3,
  NOTE_G3, NOTE_CS4,
  NOTE_C4, NOTE_FS4,NOTE_F4, NOTE_E3, NOTE_AS4, NOTE_A4,
  NOTE_GS4, NOTE_DS4, NOTE_B3,
  NOTE_AS3, NOTE_A3, NOTE_GS3,
  0, 0, 0
};

//Underworld tempo
int noteDurations[] = {
  12, 12, 12, 12, 
  12, 12, 6,
  3,
  12, 12, 12, 12, 
  12, 12, 6,
  3,
  12, 12, 12, 12, 
  12, 12, 6,
  3,
  12, 12, 12, 12, 
  12, 12, 6,
  6, 18, 18, 18,
  6, 6,
  6, 6,
  6, 6,
  18, 18, 18,18, 18, 18,
  10, 10, 10,
  10, 10, 10,
  3, 3, 3
};

Pokemon

//Pokemon melody
int melody[] = {
 0,NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4, NOTE_G4,
 NOTE_F4, NOTE_D4, NOTE_AS3, NOTE_C4,
 NOTE_G4, NOTE_G4, NOTE_F4, NOTE_DS4,
 NOTE_F4, 0,
 
 NOTE_GS4, NOTE_GS4, NOTE_GS4, NOTE_GS4, NOTE_GS4,
 NOTE_G4, NOTE_F4, NOTE_DS4, NOTE_F4,
 NOTE_G4, NOTE_G4, NOTE_F4, NOTE_DS4,
 NOTE_G4, 0, NOTE_G4, NOTE_AS4, NOTE_C5
 };
  
//Pokemon tempo
int noteDurations[] = {
  8,8,8,8,3,8,
  4,8,2,8,
  4,4,8,8,
  1,4,
  
  8,8,8,3,8,
  4,8,2,8,
  4,8,4,8,
  2,8,8,8,8
};

Star Wars

int melody[] =
{
  NOTE_F4, NOTE_F4,NOTE_F4,
  NOTE_AS4,
  NOTE_F5, NOTE_DS5, NOTE_D5, NOTE_C5,
  NOTE_AS5,
  NOTE_F5, NOTE_DS5,NOTE_D5,NOTE_C5,
  NOTE_AS5,
  NOTE_F5,NOTE_DS5,NOTE_D5,NOTE_DS5,
  NOTE_C5
};

int noteDurations[] = {
 6, 6, 6,
 1,
 2, 6, 6, 6,
 1,
 2, 6, 6, 6,
 1,
 2, 6, 6, 6,
 1};

Including Libraries in Arduino Sketches

To include libraries in your sketch, use #include. Library files use the .h file type for the headers of library folders.

Navigate to the dropdown arrow and add a new tab in your sketch in the Arduino integrated development environment (IDE). Name it "pitches.h". User-generated libraries like pitches.h will go in the subdirectory with your sketch.

Paste the code from this link https://www.arduino.cc/en/Tutorial/ToneMelody?action=sourceblock&num=2

Navigate to the Sketch>Show Sketch Folder and make sure your .h file is there.

For more on libraries, see https://www.arduino.cc/en/Hacking/Libraries

 

Play the Melody

To put it all together:

1. Include your pitches.h library.

2. Declare your variables for your input sensor and threshold.

3. Create and declare an integer array of your notes using the names referenced in pitches.h. Use empty straight brackets after array name to indicate that data is to be added but no size is given, and curly brackets to fill in your data. (Your for loop will access your arrays.) 

4. Repeat step 3 by creating an array of note durations. (You can name these arrays whatever you want, just make sure you stay consistent.)

5. In the loop() function, use the analogRead() function to get the input data from piezo 1.

6. Start your if/else statement that if the input data from piezo 1 is greater than or equal to the threshold declared at the top, start the action.

7. Use a for() statement. There are three parts to the for loop header:

for (initialization; condition; increment) {

For initialization, declare an integer (int) for the first note in your melody. For condition, count how many notes are in your melody array and have integer < #. For increment, use the compound operator ++ to increment from 0-your last note. This for loop plays the notes in succession.

8. In order to determine how long each note should be played, declare an integer to store the duration of the note. Use the assignment operator (=) to set this integer equal to the length of a whole note (I used 1200 but you can use 1000 milliseconds) divided by (/) your second array crossed with your first array []. This aligns the order of the notes with the order of durations.

9. Next, use the tone(function). There are three parts to the tone function:

tone(pin, frequency, duration);

First set your pin to digital pin 8 where piezo 2 is connected. Second, set the frequency to your first array melody [] by the declared incremented thisNote. Third, set your duration to your newly declared integer noteDuration.

10. Next declare an integer for a delay between notes and set it equal to the noteDuration multiplied (*) by 1.3.

11. Use the delay() function to set the time of delay between notes in milliseconds.

12. Use the noTone() function to stop the tone from playing at the end, since it is in the void loop() function.

13. Check all semicolons and brackets.

 
/*
  Arduino Gravity Falls Theme
*/
#include "pitches.h"
const int knockSensor = A0; // the piezo is connected to analog pin 0
const int threshold = 100;  // threshold value to decide when the detected sound is a knock or not
int sensorReading = 0;      // variable to store the value read from the sensor pin
//Gravity Falls theme melody
int melody[] = {
 NOTE_D5, NOTE_E5, 
 NOTE_F5, 
 NOTE_A5, NOTE_G5, NOTE_A5,
 NOTE_C5,
 NOTE_D5, NOTE_E5, 
 NOTE_F5, NOTE_E5,
 NOTE_G5, NOTE_A5,
 NOTE_G5, NOTE_F5,
 0, NOTE_F5, NOTE_F5, NOTE_F5, 
 NOTE_A5, NOTE_A5, NOTE_G5, NOTE_F5,
 0, NOTE_A5, NOTE_A5, NOTE_A5,
 NOTE_G5, NOTE_A5, NOTE_G5, NOTE_F5,
 
 0, NOTE_F5, NOTE_F5, NOTE_F5, 
 NOTE_A5, NOTE_A5, NOTE_G5, NOTE_F5,
 0, NOTE_A5, NOTE_A5, NOTE_A5,
 0, NOTE_CS6, NOTE_C6, NOTE_C6,
 
  0, NOTE_F5, NOTE_F5, NOTE_F5, 
 NOTE_A5, NOTE_A5, NOTE_G5, NOTE_A5,
 0, NOTE_A5, NOTE_A5, NOTE_A5,
 NOTE_G5, NOTE_C6,
 NOTE_A5, NOTE_CS6,
 
 NOTE_D4, NOTE_A4, NOTE_F4, NOTE_D5, 
 NOTE_A4, NOTE_F5, NOTE_D5, NOTE_A5, NOTE_D6
 };
  
//Gravity Falls tempo
int noteDurations[] = {
  2,4,
  1,
  3,3,4,
  1,
  
  2,4,
  2,2,
  2,2,
  2,2,
  
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  
  4,4,4,4,
  4,4,4,4,
  4,4,4,4,
  2,2,2,2,
  
  8,8,8,8,
  8,8,8,8
};

void setup() {
  
}
  void loop() {
     // read the sensor and store it in the variable sensorReading:
  sensorReading = analogRead(knockSensor);
  
  //begin if/else statement testing that knock has occurred
   if (sensorReading >= threshold) {
     
  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < 71; thisNote++) {
    // to calculate the note duration, take one second 
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1200/noteDurations[thisNote];
    tone(8, melody[thisNote],noteDuration);
    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(8);
    } 
  }
  else{
  }
 }

 

University of Florida Home Page

This page uses Google Analytics - (Google Privacy Policy)

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.