0

The program plays a random mp3 file from an Adafruit mp3 breakout board. The trigger to play the song is a sharp IR sensor. Basically to play a file you pass your hand over the sensor and it plays the full track. If you want to stop the file playing pass your hand over again and it switches it to an off mode.

I wrote a while statement using millis() to keep track of time. I would like for the songs to keep playing for a defined time or if you pass your hand over it, it stops playing the music.

Right now it's only playing a single file. It appears that the if statement I have in the while loop is being ignored. The program goes straight to break when the file is played.

//----------------------------------------------------------
// MUSIC PLAYER
// vonderasche
// 3/26/2017
//----------------------------------------------------------

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include <SharpIR.h>

// constants
#define ir A4
#define model 1080
#define TRIGGER_PIN  5
#define ECHO_PIN     6
#define MAX_DISTANCE 200

// These are common pins between breakout and shield
#define DREQ 3
// VS1053 Data request, ideally an Interrupt pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define CARDCS 4 // Card chip select pin
// These are the pins used for the breakout example
#define BREAKOUT_DCS 8
// VS1053 Data/command select pin (output)
// used to be pin 8
#define BREAKOUT_RESET  9 // VS1053 reset pin (output)
#define BREAKOUT_CS     10 // VS1053 chip select pin (output)

Adafruit_VS1053_FilePlayer musicPlayer =
// create breakout-example object!
Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS,     DREQ, CARDCS);

SharpIR SharpIR(ir, model);

int state = 1;
const unsigned long onTimer = 1200000;

/// File listing helper
void printDirectory(File dir, int numTabs) {
  while (true) {
    File entry = dir.openNextFile();
    if (!entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i<numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}

// random seed function
int rNumbers(int rNum) {
  randomSeed(analogRead(3));
  rNum = random(1, 10);
  return rNum;
}

// play a certain file
void playFile(int rNum) {
  switch (rNum) {
    case 1:
      Serial.println(F("Playing track 001"));
      musicPlayer.startPlayingFile("track001.mp3");
      break;
    case 2:
      Serial.println(F("Playing track 002"));
      musicPlayer.startPlayingFile("track002.mp3");
      break;
    case 3:
      Serial.println(F("Playing track 003"));
      musicPlayer.startPlayingFile("track003.mp3");
      break;
    case 4:
      Serial.println(F("Playing track 004"));
      musicPlayer.startPlayingFile("track004.mp3");
      break;
    case 5:
      Serial.println(F("Playing track 005"));
      musicPlayer.startPlayingFile("track005.mp3");
      break;
    case 6:
      Serial.println(F("Playing track 006"));
      musicPlayer.startPlayingFile("track006.mp3");
      break;
    case 7:
      Serial.println(F("Playing track 007"));
      musicPlayer.startPlayingFile("track007.mp3");
      break;
    case 8:
      Serial.println(F("Playing track 008"));
      musicPlayer.startPlayingFile("track008.mp3");
      break;
    case 9:
      Serial.println(F("Playing track 009"));
      musicPlayer.startPlayingFile("track009.mp3");
      break;
    case 10:
      Serial.println(F("Playing track 010"));
      musicPlayer.startPlayingFile("track010.mp3");
      break;
    }
  }

void setup() {
  Serial.begin(9600);
  Serial.println("Adafruit VS1053 Simple Test");
  if (!musicPlayer.begin()) {
    // initialise the music player
    Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
    while (1);
  }
  Serial.println(F("VS1053 found"));
  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1); // don't do anything more
  }
  // list files
  printDirectory(SD.open("/"), 0);
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(30, 30);
  // Timer interrupts are not suggested, better to use DREQ interrupt!
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT);
  // timer int
  // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background
  // audio playing
  musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int
}

void loop() {
  // calls random number function
  int randomNumber;
  // takes distance measurment
  float distance = (SharpIR.distance() / (2.4));
  static enum { ON, OFF } state;
  // if distance range is between certain values switch the state
  if (distance > 1 && distance < 12) {
    switch (state) {
      case ON:
        {
        unsigned long previousMillis = millis();
        unsigned long currentMillis = millis();
        while ((currentMillis - previousMillis) < onTimer) {    
          Serial.println("inside while loop");
          randomNumber = rNumbers(randomNumber);
          // calls random number function
          playFile(randomNumber); // plays music file
          float distance2 = (SharpIR.distance() / (2.4));
          delay(1000);
          //breaks timer if hand swipe
          if (distance2 > 2 && distance2 < 8) {
            Serial.println("Break");
            break;
          }
          currentMillis = millis();
        }
        state = OFF;
      }
      break;
    case OFF:
      {
      Serial.println("Triggered Off");
      musicPlayer.stopPlaying();
      state = ON;
      }
      break;
    }
  };
}
1

There's probably a good chance that when you trigger the ON state by placing your hand close to the sensor, the while loops runs and hits the if statement before you have moved your hand out of the trigger distance.

I see the delay of 1 second before the if, however, you take the reading of the IR sensor before the delay.

Try the delay before reading the sensor:

        ...
        playFile(randomNumber);  // plays music file

        delay(1000); // let the user move their hand
        float distance2 = (SharpIR.distance() / (2.4));

        //breaks timer if hand swipe
        if (distance2 > 2 && distance2 < 8)
        {
        ...

If you wanted to remove the delay function (highly recommended) after playing the file, set the state to something like PLAYING.

Then in the PLAYING state switch case you first wait for an IR reading that there is no hand present (allowing the user to finish moving their hand away), set a flag that you are ready to detect the hand. Then if that flag is true and the IR sensor reads a hand, then you can move to the OFF state.

You can add a second condition to the PLAYING state to test for elapsed time as well.

| improve this answer | |
  • that seems to work. Ill look into trying to implement a flag setup later. – Michael Niebauer Mar 29 '17 at 3:40
1

The intent of some of your code isn't clear, and the description “The program goes straight to break when the file is played” looks wrong – it appears that at least one delay(1000) will occur between start and break, so perhaps you mean that about a second after playing starts, it breaks.

If so, here is a possible explanation of that behavior:

  1. At the beginning of loop(), you say distance = (SharpIR.distance() / (2.4));

  2. Suppose that results in a value between 2 and 8. Then the if condition (distance > 1 && distance < 12) will be true, so the body of the if will execute.

  3. state initially is ON (state is static, and per §6.7.9.10 of the N1570 C++ spec, apparently gets initialized to 0, which corresponds to ON) and will be ON after each execution of the OFF case in loop().

  4. When state is ON, we proceed into the ON case of the switch, set some variables to current time, then use a few microseconds to serial-print and call rNumbers() and playFile(). Then distance2 = (SharpIR.distance() / (2.4)); sets distance2 to about the same value read a few microseconds earlier into distance; as we supposed earlier, a number between 2 and 8.

  5. With delay(1000), the program sits for a second doing nothing and paying attention to nothing.

  6. The (distance2 > 2 && distance2 < 8) condition for the next if is true, so program prints "Break", breaks out of the while, turns off state, breaks out of the switch, exits loop(), enters loop(), etc.

However, now that a second has gone by, the Sharp sensor shouldn't be reading a gesture. If it is, that will allow the OFF case to execute and call musicPlayer.stopPlaying().


Note, issue the randomSeed(analogRead(3)) call only once, and do so within setup(). Calling it within each rNumbers() call is going to give you non-random numbers.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.