Learn Arduino with Olympia Circuits
Learn Arduino
  • Home
    • Get Started
    • How to Use This Site
  • Electronics
    • The Basics
    • Electricity Flows like Water
    • Electronic Components
    • The Arno Board
  • Programming
    • The Basics
    • setup and loop Blocks
    • Variables and Arrays
    • Connecting with the Pins
    • Flow Control >
      • if Statement
      • Loops
      • Delays
    • Functions
    • Serial Communication
    • USB
    • Some Thoughts
  • Projects
    • Projects 1 >
      • 1.01: Blink
      • 1.02 Blink x2
      • 1.03 Blink Faster
      • 1.04 LED Chase!
      • 1.05 Wait To Blink
      • 1.06 Blink a Little Faster Now
      • 1.07 LED Fade
      • 1.08 RGB Blink
      • 1.09 Change RGB Color with SW1
      • 1.10 Fade RGB Colors
      • 1.11 Reaction Time Game
    • Projects 2 >
      • 2.01 Hello World
      • 2.02 Talk Back
      • 2.03 ASCII Values
      • 2.04 Ski Game
      • 2.05 Demonstration of the String Object
    • Projects 3 >
      • 3.01 Read the Potentiometer
      • 3.02 ASCIIbet Soup
      • 3.03 Potentiometer sets LED Brightness
      • 3.04 Potentiometer Sets Blink Rate
      • 3.05 LED Chase, Part II
    • Projects 4 >
      • 4.01 Bringing the Piezo to Life
      • 4.02 Controlling the Piezo with a Function
      • 4.03 Piezo C Major
      • 4.04 Piezo Greensleaves
      • 4.05 Piezo Metronome
      • 4.06 Piezo as an Input
      • 4.07 Piezo as an Input 2
      • 4.08 Metronome II
      • 4.09 Piezo Playback
      • 4.10 Piezo Fireworks
      • 4.11 Piezo Mosquito
    • Projects 5 >
      • 5.01 The Phototransistor
      • 5.02 Light and Sound
      • 5.03 Light and Sound II
    • Projects 6 >
      • 6.01 EEPROM
      • 6.02 I2C Address Scan
      • 6.03 Read the I2C Temperature Sensor
      • 6.04 High Temperature Alarm
    • Projects 7 >
      • 7.01 Arno Phone Home
      • 7.02 Keyboard Alphabet
      • 7.03 Move Mouse
      • 7.04 Draw Squares
    • Special Projects >
      • Bike Light Demo
  • References
    • Arno Pin Key
    • Arno Schematic
    • Project Index

Project 4.08 Metronome II

 In this project, we sense taps on the piezo to set the beat of a metronome.  This requires us to use the piezo as both an input, to record the taps, and as an output, to play back the tones. The piezo records four taps and then emits beeps at the average rate of the four taps.  We use the red channel of the RGB LED to indicate when a tap has been recorded. 

We set up SW1 as our reset.  Upload this sketch and tap on the piezo four times.  We print the tempo to the serial monitor, so open it once the sketch has been uploaded.  It will play back the tempo until you hold down SW1.  This resets the Arno and gets it ready for four more taps.


Concepts:  analogRead, boolean variable type, functions, switching pinMode

Circuits:
  • Circuit 2
  • Circuit 3
  • Circuit 4


  • Select Sketch

    ///////////////////////////////////////////////////
    //Project 4.08 Piezo Metronome II
    int piezo = A11;
    int knock = 0;
    int redLED = 9;
    int SW1 = 1;
    long periods;
    long beats;
    long times[4];
    int count = 0;
    int playback = 0;
    void setup(){
    Serial.begin(9600);
    clearPiezo();
    pinMode(redLED,OUTPUT);
    pinMode(SW1,INPUT);
    }
    void loop(){
    knock = analogRead(piezo);
    if(knock > 40){
    times[count] = millis();
    digitalWrite(redLED,HIGH);
    delay(50);
    digitalWrite(redLED,LOW);
    count ++;
    while(knock > 20){
    clearPiezo();
    knock = analogRead(piezo);
    }
    }
    if(count==4){
    pinMode(piezo,OUTPUT);
    count = 0; //reset for next time
    periods = 0;
    //calculate periods
    for(int j = 0; j<3; j++){
    //measure the time between beats
    periods = periods + times[j+1] - times[j];
    }
    periods = periods/3;
    if(periods < 50) periods = 51;
    Serial.print(Beats per Minute = );
    Serial.println(60L*1000L/periods);
    //now play back until SW1 pressed
    while(digitalRead(SW1)==HIGH){
    //create tone
    digitalWrite(redLED,HIGH);
    piezoTone(2500,50);
    digitalWrite(redLED,LOW);
    delay(periods-50);
    } //end if for SW1 pressed
    //turn piezo back to an input
    while(digitalRead(SW1)==LOW){
    clearPiezo();
    }
    }
    }
    void clearPiezo(){
    pinMode(piezo,OUTPUT);
    digitalWrite(piezo,LOW);
    delay(1);
    pinMode(piezo,INPUT);
    }
    void piezoTone(long freq, long duration){
    long aSecond = 1000000;
    long period = aSecond/freq;
    duration = duration*1000;
    duration = duration/period;
    for(long k = 0; k < duration; k++){
    digitalWrite(piezo,HIGH);
    delayMicroseconds(period/2);
    digitalWrite(piezo,LOW);
    delayMicroseconds(period/2);
    }
    }
    ///////////////////////////////////////////////////

    In the start of the program, we declare a long array to hold the millis() values of each tap:

    long times[4];

    In the setup() block we set up the piezo using our clearPiezo function:

    clearPiezo();

    Like project 4.07, we record the value from analogRead using the variable knock.  If a strike is detected, we record the time in the array times and flash the redLED.  Next, we increment count to record the number of strikes.  We use count to move through the times array and to tell when four strikes have been recorded. 

     knock = analogRead(piezo);

     if(knock > 40){

        times[count] = millis();

        digitalWrite(redLED,HIGH);

        delay(50);

        digitalWrite(redLED,LOW);

        count ++;

    Before exiting the if block, we make sure that the piezo pin has been brought back to near zero.  We use a while  loop and one or more calls to clearPiezo to reset the piezo pin:

        while(knock > 20){

          clearPiezo();

          knock = analogRead(piezo);

        }

      }

    The variable count tracks how many taps have been recorded.  One we record 4 taps we switch to playback mode.  At this point we switch the pinMode of the piezo to an output:

    if(count==4){

        pinMode(piezo,OUTPUT);

        count = 0; //reset for next time

        periods = 0;

    Next we want to calculate the time lapse between taps:

    //calculate periods

        for(int j = 0; j<3; j++){

          //measure the time between beats

          periods = periods + times[j+1] - times[j];    

        }

        periods = periods/3;

    We output the results to the serial monitor.  Metronomes usually are set in beats per minute so we convert the value from milliseconds to beats per minute for the user.  We also don’t allow values of < 50 milliseconds (that would be 12000 beats per minute!):

        if(periods < 50) periods = 51;

        Serial.print("Beats per Minute = ");

        Serial.println(60L*1000L/periods);

    Notice that when we calculate the beats per minute in the last line above, we put an ‘L’ at the end of the numbers 60 and 1000.  This tells the sketch to treat these numbers as long variable types.  Without the ‘L’, the sketch might treat theses as int variables, which would ruin our calculation.

    We now playback the beat until SW1 is pressed:

    //now play back until SW1 pressed

        while(digitalRead(SW1)==HIGH){   

          //create tone

          digitalWrite(redLED,HIGH);

          piezoTone(2500,50);

          digitalWrite(redLED,LOW);

    Since the tone lasts of 50 milliseconds, we subtract that from the delay between tones to keep on the beat:

          delay(periods-50);

    Once we break out of the while loop, we clear the piezo before starting the process over again:

        //clear piezo while button is pressed

        while(digitalRead(SW1)==LOW){

          clearPiezo();

        }

    Back to Projects 4

    Copyright Olympia Circuits LLC 2014. All Rights Reserved.