Momentary On/ Off switch

Hi Guys,

I apologise in advance if these questions are incredibly simple/ over asked. My understand of Arduinos are much below elementary. I have a project which involves creating a simple musical device based on a PING Distance sensor. Currently I have several cases set up which change notes based on distance.

Now what I would like to do is be able to turn the system on and off using a momentary switch which would be able to interrupt any loop.

I have tried if/ else structures, while structures and that would probably be the limit of my understanding. The difficult/ more advanced sections of this code has been created with help from my tutor and I find myself looking at it quite blankly.

Below is the code:

int redPin = 9;
int greenPin = 10;
int bluePin = 11;
const int pingPin = 7;
int speakerOut = 8;
int button = 2;
int onlight = 13;
// Do we want debugging on serial out? 1 for yes, 0 for no

boolean noNote = false;
int noteRead;
int numReadNotes=0;

#include "pitches.h"


// notes in the melody:

int melodyA[] = {
  0,0,4,4,5,5,4,3,3,2,2,1,1,0};

float accuracy=0;

int melodyLength = 14;

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




void setup(){
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(speakerOut, OUTPUT);
  pinMode(button, INPUT);
  pinMode(onlight, OUTPUT);
  Serial.begin (9600);

  int state = HIGH;      // the current state of the output pin
  int reading;           // the current reading from the input pin
  int previous = LOW;    // the previous reading from the input pin

  // the follow variables are long's because the time, measured in miliseconds,
  // will quickly become a bigger number than can be stored in an int.
  long time = 0;         // the last time the output pin was toggled
  long debounce = 200;   // the debounce time, increase if the output flickers

  if (reading == HIGH && previous == LOW && millis() - time > debounce) {
    if (state == HIGH)
      state = LOW;
    else
      state = HIGH;

    time = millis();    
  }

  if(state == LOW){
    digitalWrite(onlight, HIGH); } 
  else {

    buzz(speakerOut, c, 500);
    buzz(speakerOut, g, 300);
    delay(50);
    buzz(speakerOut, g, 200);
    buzz(speakerOut, c, 500);
    delay( 1000);
  }



}

void loop()
{
  //selectSong();

  accuracy = 0;


  playSong();
  readNotes();



  //for (int i =0 ; i < songLength; i++){


  float accPercent = accuracy/melodyLength;
  Serial.print("Accuracy is ");
  Serial.print(accPercent*100);
  Serial.print("% ");
  Serial.println("");

  Serial.print(digitalRead(button));
}




void playSong(){
  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < melodyLength; thisNote++) {

    int noteDuration = 1000/noteDurations[thisNote];
    playNote(melodyA[thisNote],noteDuration); 
  }




}




void readNotes(){
  //reset readNotes (how many notes have been read?)
  numReadNotes = 0;

  while (numReadNotes< melodyLength){

    // establish variables for duration of the ping, 
    // and the distance result in inches and centimeters:
    long duration, cm;

    // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
    // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
    pinMode(pingPin, OUTPUT);
    digitalWrite(pingPin, LOW);
    delayMicroseconds(2);
    digitalWrite(pingPin, HIGH);
    delayMicroseconds(5);
    digitalWrite(pingPin, LOW);

    int buttonState = 0;
    buttonState = digitalRead(button);

    // The same pin is used to read the signal from the PING))): a HIGH
    // pulse whose duration is the time (in microseconds) from the sending
    // of the ping to the reception of its echo off of an object.
    pinMode(pingPin, INPUT);
    duration = pulseIn(pingPin, HIGH);

    // convert the time into a distance
    cm = microsecondsToCentimeters(duration);

    //   Serial.print(cm);
    //   Serial.print("cm");

    if (cm <=80){

      noteRead = int(cm/10);
      //compare
      if (noteRead == melodyA[numReadNotes-1]){
        accuracy++;
      }

      if (noNote) {
        numReadNotes++;
      }
      noNote = false;
    } 
    else {
      noNote = true;
      noteRead = 8;
    }

    playNote(noteRead, 200);

  }
}

void playNote(int note, int length){

  switch (note) {
  case 0: 
    //Serial.println("Zero"); 
    analogWrite(redPin, 255);      // RED
    analogWrite(greenPin, 0);
    analogWrite(bluePin, 0);
    buzz(speakerOut, c, length);
    break;
  case 1:
    analogWrite(redPin, 255);      // VIOLET
    analogWrite(greenPin, 0);
    analogWrite(bluePin, 255);
    buzz(speakerOut, d, length);
    break;
  case 2:
    analogWrite(redPin, 0);        // GREEN
    analogWrite(greenPin, 255);
    analogWrite(bluePin, 0);
    buzz(speakerOut, e, length);
    break;
  case 3:
    analogWrite(redPin, 255);      // YELLOW
    analogWrite(greenPin, 255);
    analogWrite(bluePin, 0);
    buzz(speakerOut, f, length);
    break;
  case 4:
    analogWrite(redPin, 0);        //  BLUE
    analogWrite(greenPin, 0);
    analogWrite(bluePin, 255);
    buzz(speakerOut, g, length);
    break;
  case 5:
    analogWrite(redPin, 255);        //  ORANGE
    analogWrite(greenPin, 30);
    analogWrite(bluePin, 0);
    buzz(speakerOut, a, length);
    break;
  case 6:
    analogWrite(redPin, 0);        //  CYAN
    analogWrite(greenPin, 255);
    analogWrite(bluePin, 255);
    buzz(speakerOut, b, length);
    break;
  case 7:
    analogWrite(redPin, 255);        //  PINK
    analogWrite(greenPin, 0);
    analogWrite(bluePin, 50);
    buzz(speakerOut, C, length);
    break;
  case 8:
    // Serial.println("over 80");
    analogWrite(redPin, 255);        //  WHITE
    analogWrite(greenPin, 255);
    analogWrite(bluePin, 255);
    buzz(speakerOut, 100000, 0);
    break;
  case 9:
    digitalWrite(onlight, LOW);//off
  }
}


long microsecondsToInches(long microseconds)
{
  // According to Parallax's datasheet for the PING))), there are
  // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
  // second).  This gives the distance travelled by the ping, outbound
  // and return, so we divide by 2 to get the distance of the obstacle.
  // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
  return microseconds / 74 / 2;
}

long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}

long microsecondsToMilimetres(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / .2 ;
}

void buzz(int targetPin, long frequency, long length) {
  long delayValue = 1000000/frequency/2; // calculate the delay value between transitions
  //// 1 second's worth of microseconds, divided by the frequency, then split in half since
  //// there are two phases to each cycle
  long numCycles = frequency * length/ 1000; // calculate the number of cycles for proper timing
  //// multiply frequency, which is really cycles per second, by the number of seconds to 
  //// get the total number of cycles to produce
  for (long i=0; i < numCycles; i++){ // for the calculated length of time...
    digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphram
    delayMicroseconds(delayValue); // wait for the calculated delay value
    digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphram
    delayMicroseconds(delayValue); // wait again for the calculated delay value
  }
}

Would someone please be kind enough to help.

You can have a global variable set by an interrupt (ie the button), then check that variable everywhere you have code that runs loops etc. In other words just about everywhere. When you detect the variable is set you have to back out of every function until you are back at the top level.

That will be a real pain, so here's a quick and dirty way.

Have the button trigger an interrupt and also read it from a pin, on power up wait for the button to be released then pressed again then enable the interrupt. When you get the interrupt restart the program

asm ("jmp 0");

This causes the program to wait for the button again.

There may be a better way and I'll probably cop some flack for suggesting a restart but that's the best I can think of right now as a quick retro fit to the existing program.

PS, your teacher/tutor may not like it :)


Rob