How to start my project with a button?

I'm making a speaking skull. Found lot's of info, and finally I've got it to work.
I am using an arduino mega with a adafruit MP3 shield VS1053 on top of it.
It works fine, but to (re-)start it you have to press the reset button. I want the arduino on, and as soon as a button is pressed it start to play the words.

I did found an answere on Reddit: https://www.reddit.com/r/arduino/comments/2bdurt/starting_the_loop_with_the_press_of_a_button/
They proposed :
void loop() { while (digitalread(pin) == LOW) {};
while (1) { // do stuff here, the loop will always repeat } }

or even better at the bottom of the setup()
while (digitalread(pin) == LOW) {}
Then you don't need "while (1) {...}". This is in the code

I tried to put the "{" and "}" almost every where, but I don't get it to work.
BTW: the button has 5 v incomming from the mega, outgoing 10K to gnd and a connection to pin 2.
What do I wrong?

[code]
/*17AUG21 
    Scope is: when skeleton is outside the coffin, the jaw moves with the spoken words.
    This will be activated when the end switch is made. (Have to implement this switch).

    jawservo works and eyeleds are working.

*/

/***************************************************

  Designed specifically to work with the Adafruit VS1053 Music Maker shield
  ----> https://www.adafruit.com/product/1788

 ****************************************************/

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

Servo jaw;                  // Creates a servo object called jaw
const int jawPin = 8;       // Connect jaw to Pin 8

const int ledPin = 9;       // Led's on Pin 9
int audioVal = 0;           // 
const int audioPin =  0;    // Connect to audio output to AI Pin 0
const int buttonPin = 2;    // Switch Case Open contact connect to Pin 2
int buttonState = 0;        // Variable for reading S(witch)C(coffin)O(pen) contact

int busy;

// See http://arduino.cc/en/Reference/SPI "Connections"


// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer =
  
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

void setup()
{
  Serial.begin(9600);
  jaw.attach(jawPin);          // Attaches the jawservo on jawPin
  jaw.write(-90);                // Put servo on -90 degrees
  pinMode(jawPin, OUTPUT);
  pinMode (buttonPin, INPUT);
  pinMode (ledPin, OUTPUT);   // set pin as output
  pinMode (ledPin, HIGH);     // set pin HIGH or LOW

  Serial.println("Adafruit VS1053 Simple_servo 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"));

  musicPlayer.sineTest(0x88, 500);    // Make a tone to indicate VS1053 is working

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);            // don't do anything more
  }
  Serial.println("SD OK!");

  //----list files----
  printDirectory(SD.open("/"), 0);

  //----Set volume for left, right channels. lower numbers == louder volume!----
  musicPlayer.setVolume(5, 5);

  // 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

  // Play one file, don't return until complete   //Important, track name: 8  letters dot 3 letters.
  //Serial.println(F("Playing track 001"));
  // musicPlayer.playFullFile("/track001.mp3");
  // Play another file in the background, REQUIRES interrupts!
  Serial.println(F("Playing track 002"));
  musicPlayer.startPlayingFile("/track002.mp3");


  while (digitalRead(buttonPin) == LOW){};
}


void loop() {

  musicplayer();

}


void musicplayer()
{
  int val = analogRead(audioPin);
  val = map(val, 250, 1023, 15, 45);    // Analog input between 0 and 1023 --> digital output between 0 and 255
  jaw.write(val);
  audioVal = analogRead(audioPin);      // Read the audioPin
  digitalWrite(ledPin, audioVal);   // Light up the LED's. (original: audioVal / 4)
  
  {
    busy = analogRead(audioPin);



    // File is playing in the background
    if (musicPlayer.stopped()) {
      Serial.println("Done playing music");
      while (1) {
        delay(10);  // we're done! do nothing...
      }
    }
    if (Serial.available()) {
      char c = Serial.read();

      // if we get an 's' on the serial console, stop!
      if (c == 's') {
        musicPlayer.stopPlaying();
      }

      // if we get an 'p' on the serial console, pause/unpause!
      if (c == 'p') {
        if (! musicPlayer.paused()) {
          Serial.println("Paused");
          musicPlayer.pausePlaying(true);
        } else {
          Serial.println("Resumed");
          musicPlayer.pausePlaying(false);
        }
      }
    }

    delay(100);
  }
}


/// File listing helper
void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      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();
  }
}
[/code]

Here is a problem. Once the music stops you enter an infinite loop. You are stuck there.

    if (musicPlayer.stopped()) {
      Serial.println("Done playing music");
      while (1) {
        delay(10);  // we're done! do nothing...
      }
    }

Thanks, ToddL 1962 for the quick respons. I did change that in:

 if (musicPlayer.stopped()) {
      Serial.println("Done playing music");
      while (0) {                             // original (1)
        //delay(10);  // we're done! do nothing...

The result is by starting up, the loop wil run only the spoken words (only sound).
When the button is pressed, the servo (jaw) does it's movements without sound, after that the leds will do their trick, no sound, but goes forever.

I understand most of the code (80 %) but can't find out where it goes wrong. I hope you or someone else can push me in the right direction.

void loop() {
 if ( (digitalread(pin) == LOW) {
  // your loop stuff
 }
}

... assuming your button is active LOW.
As soon as your "loop stuff" is finished, the loop() resumes and waits for the button to go LOW again...

That is also a flaw I think. It is connected as mentioned above, which is with a pull-down resistor, so when the button is pressed, active HIGH.
So I changed that in the setup :

  Serial.println(F("Playing track 002"));
  musicPlayer.startPlayingFile("/track002.mp3");

  while (digitalRead(buttonPin) == HIGH) {}; //Original LOW
}

void loop()
{
  musicplayer();
}

Nothing changed.

Then I placed your code in the void loop () -without one '(' before (digitalread(pin)... :slight_smile: -
But then I do get a failure:

exit status 1
'musicplayer' was not declared in this scope

So, last option was to put it behind void musicplayer() :

void musicplayer(){
if (digitalRead (buttonPin) == HIGH)
{
  int val = analogRead(audioPin);
  val = map(val, 250, 1023, 15, 45);    // Analog input between 0 and 1023 --> digital output between 0 and 255
  jaw.write(val);
  audioVal = analogRead(audioPin);      // Read the audioPin
  digitalWrite(ledPin, audioVal);   // Light up the LED's. (original: audioVal / 4)

  {
    busy = analogRead(audioPin);



   // File is playing in the background
    if (musicPlayer.stopped()) {
      Serial.println("Done playing music");
      while (0) {                             // original (1)
        delay(10);  // we're done! do nothing...
      }
    }

    if (Serial.available()) {
      char c = Serial.read();

      // if we get an 's' on the serial console, stop!
      if (c == 's') {
        musicPlayer.stopPlaying();
      }

      // if we get an 'p' on the serial console, pause/unpause!
      if (c == 'p') {
        if (! musicPlayer.paused()) {
          Serial.println("Paused");
          musicPlayer.pausePlaying(true);
        } else {
          Serial.println("Resumed");
          musicPlayer.pausePlaying(false);
        }
      }
    }

    delay(100);
  }
}
}

It will play the sound once, no servo, no led's, the serial monitor shows: Done play music. Pressing the button, gives a little bit of life in the servo and led's. The serial monitor shows in the same second: Done playing music, Done playing music.

Seems like after pressing the button, it is doing something. Will read the code some more time en try to understand it further.

Your LED brightness and jaw movement is based on the audio. When you press the button you never restart the music file, therefore there is no audio to trigger the jaw or LED. In loop() why don't you just check to see if the button is pressed and if it is restart the music?

If the library is multitasking via non-blocking code, the simple code I posted would not work in all maybe most cases. Most functions depend on an update method that has to be continuously called in loop(). But, it would be easy to do using the typical state machine.

If the library has pause and resume methods, it should be easy to use those to control the audio based on input from push buttons or sensors. Meanwhile the update method runs on...

Such a program mainly has two parts, button processing and main program which contains sound and sequencing code, if I understand correctly. Communication is usually through flags, shared variables and buffers.

1 Like

Okay, the first part I understand, but I also tried it at the very top of the loop(), but than I do get the failures. I did read and searched a lot tonight an found this on de arduinosit:

int run;
int buttonPin;

void setup()
{
   run = 0; //starts stopped
   buttonPin = 7; //whatever pin your button is plugged into

   pinMode(buttonPin, INPUT_PULLUP);
}

void loop()
{
   //code you always run here; you can leave this section blank if you want the entire program to stop and start, or add code here if you want it to always run

   //check button press here and if it is pressed then toggle run variable between 0 and 255; REQUIRED!
   if(digitalRead(buttonPin) == LOW) //funcitons based off of button pulling input pin LOW
   {
      if(run == 0)
      {
          run = 255;
      }
      else
      {
          run = 0;
      }
   }

   if(run > 0)
   {
      //code you only run if button was pressed, stops running when button pressed again, so forth...
   }
}

And implemented as follow:

[code]
/*18bAUG21
    Scope is: when skeleton is outside the coffin, the jaw moves with the spoken words.
    This will be activated when the end switch is made. (Have to implement this switch).

    jawservo works and eyeleds are working.

*/

/***************************************************

  Designed specifically to work with the Adafruit VS1053 Music Maker shield
  ----> https://www.adafruit.com/product/1788

 ****************************************************/

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

Servo jaw;                  // Creates a servo object called jaw
const int jawPin = 8;       // Connect jaw to Pin 8

const int ledPin = 9;       // Led's on Pin 9
int audioVal = 0;           //
const int audioPin =  0;    // Connect to audio output to AI Pin 0
const int buttonPin = 2;    // Switch Case Open contact connect to Pin 2
int buttonState = 0;        // Variable for reading S(witch)C(coffin)O(pen) contact

int busy;

int run; //

// See http://arduino.cc/en/Reference/SPI "Connections"


// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer =

  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

void setup()
{
  Serial.begin(9600);
  jaw.attach(jawPin);          // Attaches the jawservo on jawPin
  jaw.write(-90);                // Put servo on -90 degrees
  pinMode(jawPin, OUTPUT);
  pinMode (buttonPin, INPUT);
  pinMode (ledPin, OUTPUT);   // set pin as output
  pinMode (ledPin, HIGH);     // set pin HIGH or LOW


  run = 0; // starts stopped  //

  Serial.println("Adafruit VS1053 Simple_servo 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"));

  musicPlayer.sineTest(0x88, 500);    // Make a tone to indicate VS1053 is working

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);            // don't do anything more
  }
  Serial.println("SD OK!");

  //----list files----
  printDirectory(SD.open("/"), 0);

  //----Set volume for left, right channels. lower numbers == louder volume!----
  musicPlayer.setVolume(5, 5);

  // 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

  // Play one file, don't return until complete   //Important, track name: 8  letters dot 3 letters.
  //Serial.println(F("Playing track 001"));
  // musicPlayer.playFullFile("/track001.mp3");
  // Play another file in the background, REQUIRES interrupts!
  Serial.println(F("Playing track 002"));
  musicPlayer.startPlayingFile("/track002.mp3");



}


void loop() {
  if (digitalRead(buttonPin) == HIGH) //funcitons based off of button pulling input pin LOW
  {
    if (run == 0)
    {
      run = 255;
    }
    else
    {
      run = 0;
    }
  }

  if (run > 0)
  {
    //code you only run if button was pressed, stops running when button pressed again, so forth...
  }

  {
    musicplayer();
  }
}

void musicplayer()
{
  int val = analogRead(audioPin);
  val = map(val, 250, 1023, 15, 45);    // Analog input between 0 and 1023 --> digital output between 0 and 255
  jaw.write(val);
  audioVal = analogRead(audioPin);      // Read the audioPin
  digitalWrite(ledPin, audioVal);   // Light up the LED's. (original: audioVal / 4)

  {
    busy = analogRead(audioPin);



    // File is playing in the background
    if (musicPlayer.stopped()) {
      Serial.println("Done playing music");
      while (1) {                             // original (1)
        delay(10);  // we're done! do nothing...
      }
    }

    if (Serial.available()) {
      char c = Serial.read();

      // if we get an 's' on the serial console, stop!
      if (c == 's') {
        musicPlayer.stopPlaying();
      }

      // if we get an 'p' on the serial console, pause/unpause!
      if (c == 'p') {
        if (! musicPlayer.paused()) {
          Serial.println("Paused");
          musicPlayer.pausePlaying(true);
        } else {
          Serial.println("Resumed");
          musicPlayer.pausePlaying(false);
        }
      }
    }

    delay(100);
  }
}


/// File listing helper
void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      //Serial.println("**nomorefiles**");
      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();
  }
}
[/code]

The good thing is, no errors. The bad thing, nothing changes. It still runs one time. Even changing this part:

if (musicPlayer.stopped()) {
Serial.println("Done playing music");
while (1) { // original (1)
delay(10); // we're done! do nothing...
or put it between /* ....*/

So how do I get the program at the end, back to the beginning of the loop?

It does go back to the beginning! Like I said in my earlier post, you NEVER restart the playback. You only started the playback in setup(). Call the following when the button is pressed:

musicPlayer.startPlayingFile("/track002.mp3");

aarg, I've spend quite some time last night with reading and try to understand the 'typical state machine'. The way you explain it sound simple, but I'll find it difficult to implement it.
So, first I will try it the 'ToddL 1962' way. Maybe I'm wrong but it looks more simple to me (for now :roll_eyes:).

I never realised that the 'start' signal was given in the setup. Thanks for pointing out that.
I will work on it. Thanks again.

First of all I want you to know I appreciate your help, ToddL1962.

Spending hours of reading, I could not get it to work. Then I found on https://forums.adafruit.com/viewtopic.php?f=31&t=79556#wrap how to implement a pushbutton, for start and stop. So I tried it and it works (ofcourse) partlially.

/*18bAUG21
    Scope is: when skeleton is outside the coffin, the jaw moves with the spoken words.
    This will be activated when the end switch (Coffin_Switch_Open) is made. 
 
*/

/***************************************************

  Designed specifically to work with the Adafruit VS1053 Music Maker shield
  ----> https://www.adafruit.com/product/1788

 ****************************************************/

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


// See http://arduino.cc/en/Reference/SPI "Connections"


// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer =     // create shield-example object!
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

Servo jaw;                         // Creates a servo object called jaw
const int jawPin = 8;       // Connect jaw to Pin 8
const int ledPin = 9;       // Led's on Pin 9

const int audioPin =  0;    // Connect to audio output to AI Pin 0
int audioVal = 0;           

const int c_s_o_Pin = 2;  // Coffin Switch Open contact connect to Pin 2

uint8_t buttonState,        // Variable for reading S(witch)C(coffin)O(pen) contact
        prevButtonState;

int busy;


void setup()
{
  Serial.begin(9600);
  jaw.attach(jawPin);          // Attaches the jawservo on jawPin
  jaw.write(-90);                // Put servo on -90 degrees
  pinMode(jawPin, OUTPUT);
  pinMode (c_s_o_Pin, INPUT);   //maybe ...INPUT_PULLUP
  buttonState = HIGH;
  prevButtonState = HIGH;
  pinMode (ledPin, OUTPUT);   // set pin as output
  pinMode (ledPin, HIGH);     // set pin HIGH or LOW


  Serial.println("Adafruit VS1053 Simple_servo 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"));

  //musicPlayer.sineTest(0x88, 500);    // Make a tone to indicate VS1053 is working

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);            // don't do anything more
  }
  Serial.println("SD OK!");

  //----list files----
  //printDirectory(SD.open("/"), 0);

  //----Set volume for left, right channels. lower numbers == louder volume!----
  musicPlayer.setVolume(5, 5);

  // 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

  // Play one file, don't return until complete   //Important, track name: 8  letters dot 3 letters.
  //Serial.println(F("Playing track 001"));
  // musicPlayer.playFullFile("/track001.mp3");
  // Play another file in the background, REQUIRES interrupts!
  Serial.println(F("Playing track 002"));
  musicPlayer.startPlayingFile("/track002.mp3");

}


void musicplayer()
{
  int val = analogRead(audioPin);
  val = map(val, 250, 1023, 15, 45);    // Analog input between 0 and 1023 --> digital output between 0 and 255
  jaw.write(val);
  audioVal = analogRead(audioPin);      // Read the audioPin
  digitalWrite(ledPin, audioVal);   // Light up the LED's. (original: audioVal / 4)

  {
    busy = analogRead(audioPin);
  }
}

void loop()
{
  ///////////////////////////////////////////////////////////////////////////////////////////
  buttonState = debounceRead(c_s_o_Pin);
  if ((LOW == buttonState) && (buttonState != prevButtonState))   //if button was just pressed
  {

    if (musicPlayer.stopped())
    {
      if (! musicPlayer.startPlayingFile("/track002.mp3")) {
        Serial.println("Could not open file track002.mp3");
        while (1);
      }
      Serial.println (F("Started playing"));
    }
    else
    {
      musicPlayer.stopPlaying();
    }
  }
  prevButtonState = buttonState;       //update prevButtonState
  ///////////////////////////////////////////////////////////////////////////////////////////
}

//Use like digitalRead. Incorporates button debouncing.
uint8_t debounceRead(int pin)
{
  uint8_t pinState = digitalRead(pin);
  uint32_t timeout = millis();
  while (millis() < timeout + 10)
  {
    if (digitalRead(pin) != pinState)
    {
      pinState = digitalRead(pin);
      timeout = millis();
    }
  }
  return pinState;

I did try to implement the 10 lines of 'void musicplayer()' everywhere, also in the 'void loop()', with and without the 'void musicplayer()' line. But the jaw won't move.

So, starting up the arduino shows in the Serial monitor:

16:23:26.736 -> Adafruit VS1053 Simple_servo Test
16:23:27.022 -> VS1053 found
16:23:27.022 -> SD OK!
16:23:27.022 -> Playing track 002

Press the button:

16:23:27.022 -> VS1053 found
16:23:27.022 -> SD OK!
16:23:27.022 -> Playing track 002
16:24:40.069 -> Started playing

That works fine. But how to get the rest working???