Neophyte needs a push in the right direction

Hello, please forgive my ignorance, but Im a learner.

Trying to code my Mega 2560 and Adafruit Music Maker shield. Looking to play an MP3 file one time when a button is pressed, and then for the LED to keep flashing on and off. Im sure its just in how Im doing the looping, just cant figure the right way around it.

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

// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins. 
// See http://arduino.cc/en/Reference/SPI "Connections"

// These are the pins used for the breakout example
#define BREAKOUT_RESET  9      // VS1053 reset pin (output)
#define BREAKOUT_CS     10     // VS1053 chip select pin (output)
#define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
// 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 breakout-example object!
  //Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
  // create shield-example object!
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
    
//define switches
const char Switch5 = 31;
const char Switch1 = 35;

//define global variables
bool pressed = false;
int dt = 500;
int flash = 800;
int CommLightPin = 28;
int Switch5LightPin = 26;
int Switch1LightPin = 30;


void setup() {
  Serial.begin(115200);
  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
  }
    
  // put your setup code here, to run once:

// setup Pin Modes
pinMode(Switch5, INPUT_PULLUP);
pinMode(Switch1, INPUT_PULLUP);
pinMode (CommLightPin, OUTPUT);
pinMode (Switch5LightPin, OUTPUT);
pinMode (Switch1LightPin, OUTPUT);

}

void loop() {


//read Switch5
bool Switch5State = digitalRead(Switch5);

if (Switch5State == pressed) {
  digitalWrite (CommLightPin, HIGH);
  digitalWrite (Switch5LightPin, HIGH);
}
else {
  digitalWrite (CommLightPin, LOW);
  digitalWrite (Switch5LightPin, LOW);
}


//read Switch1
bool Switch1State = digitalRead(Switch1);

if (Switch1State == pressed) {
  musicPlayer.playFullFile("track001.mp3");
  digitalWrite (Switch1LightPin, HIGH);
  delay(flash);
  digitalWrite (Switch1LightPin, LOW);
  delay(flash);

}
else {
  digitalWrite (Switch1LightPin, LOW);
}


}

You want your code to react when a button changes state, not if it is currently pressed. You also need to get rid of the delay() function. Look at the Blink without Delay example in the IDE (File->examples->02.digital->Blink Without Delay).

You also need to keep track of what state your program is in... waiting for a button press, playing a song, etc. so you can react properly when a button gets presses again. Think of a state machine.

Give it a try ...

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

// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins.
// See http://arduino.cc/en/Reference/SPI "Connections"

// These are the pins used for the breakout example
#define BREAKOUT_RESET  9      // VS1053 reset pin (output)
#define BREAKOUT_CS     10     // VS1053 chip select pin (output)
#define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
// 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 breakout-example object!
  //Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
  // create shield-example object!
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

//define switches
const char Switch5 = 31;
const char Switch1 = 35;

//define global variables
bool pressed = false;
int dt = 500;
unsigned long flash = 800;
int CommLightPin = 28;
int Switch5LightPin = 26;
int Switch1LightPin = 30;


void setup() {
  Serial.begin(115200);
  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
  }

  // put your setup code here, to run once:

  // setup Pin Modes
  pinMode(Switch5, INPUT_PULLUP);
  pinMode(Switch1, INPUT_PULLUP);
  pinMode (CommLightPin, OUTPUT);
  pinMode (Switch5LightPin, OUTPUT);
  pinMode (Switch1LightPin, OUTPUT);

}

boolean Switch5State = false;
boolean Switch1State = false;
boolean DoFlash      = false;

void loop() {


  //read Switch5
  if(Switch5Released()) {
    Switch5State = !Switch5State;
    if (Switch5State) {
      digitalWrite (CommLightPin, HIGH);
      digitalWrite (Switch5LightPin, HIGH);
    }
    else {
      digitalWrite (CommLightPin, LOW);
      digitalWrite (Switch5LightPin, LOW);
    }
  } 

  //read Switch1
  if (Switch1Released()){
    Switch1State = !Switch1State;
    if (Switch1State) {
      musicPlayer.playFullFile("track001.mp3");
      DoFlash = true;
      Serial.println("Flash!");
    }
    else {
      digitalWrite (Switch1LightPin, LOW);
      DoFlash = false;
    }
  }  
 if (DoFlash) Flash(); 
}

void Flash(){
  static unsigned long lastFlash = 0;
  if(millis()-lastFlash > flash){
    lastFlash = millis();
    digitalWrite(Switch1LightPin,!digitalRead(Switch1LightPin));
  }
}

boolean Switch1Released(){
  static byte lastState = HIGH;
  static unsigned long lastChange;
  static byte released = false;
  byte state = digitalRead(Switch1);
  if (lastState != state) lastChange = millis();
  if (millis() - lastChange > 30) {
     if (!state) released = true;
    }
  lastState = state;  
  if (released && state)  {
     released = false;
     return true;
  }
  return false;
}

boolean Switch5Released(){
  static byte lastState = HIGH;
  static unsigned long lastChange;
  static byte released = false;
  byte state = digitalRead(Switch5);
  if (lastState != state) lastChange = millis();
  if (millis() - lastChange > 30) {
     if (!state) released = true;
    }
  lastState = state;  
  if (released && state)  {
     released = false;
     return true;
  }
  return false;
}

What it does (should do):

  • Toggles the button states every time the buttons are released (!)
  • Switches flashing of Switch1LightPin on/off
  • Switches the CommLightPen and Switch5LightPen on/off
  • Flashing done by millis() routine

If you get a notification when the mp3 has finished you could use that also to stop flashing ...

Thanks for that. I see what is mean by keeping track of the switch state.

I did try it out, it takes a double-press of the switch to get the LEDs to activate, and the Switch1 LED doesnt light or flash at all. Ill keep looking at it.

I have simulated your hardware (as far as required) on Wokwi:

image

https://wokwi.com/projects/335098600587526739

The actual sketch is this, the #define TEST excludes the non simulated parts. Would you mind to check the way you have connected your buttons?

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

// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins.
// See http://arduino.cc/en/Reference/SPI "Connections"

// These are the pins used for the breakout example
#define BREAKOUT_RESET  9      // VS1053 reset pin (output)
#define BREAKOUT_CS     10     // VS1053 chip select pin (output)
#define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
// 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 breakout-example object!
  //Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
  // create shield-example object!
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

//define switches
const char Switch5 = 31;
const char Switch1 = 35;

//define global variables
bool pressed = false;
int dt = 500;
unsigned long flash = 800;
int CommLightPin = 28;
int Switch5LightPin = 26;
int Switch1LightPin = 30;


void setup() {
  Serial.begin(115200);
  Serial.println("Adafruit VS1053 Simple Test");
#ifdef TEST  
  // No musicplayer, no SD card required
#else
  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
  }
#endif
  // put your setup code here, to run once:

  // setup Pin Modes
  pinMode(Switch5, INPUT_PULLUP);
  pinMode(Switch1, INPUT_PULLUP);
  pinMode (CommLightPin, OUTPUT);
  pinMode (Switch5LightPin, OUTPUT);
  pinMode (Switch1LightPin, OUTPUT);

}

boolean Switch5State = false;
boolean Switch1State = false;
boolean DoFlash      = false;

void loop() {


  //read Switch5
  if(Switch5Released()) {
    Switch5State = !Switch5State;
    if (Switch5State) {
      digitalWrite (CommLightPin, HIGH);
      digitalWrite (Switch5LightPin, HIGH);
    }
    else {
      digitalWrite (CommLightPin, LOW);
      digitalWrite (Switch5LightPin, LOW);
    }
  } 

  //read Switch1
  if (Switch1Released()){
    Switch1State = !Switch1State;
    if (Switch1State) {
#ifdef TEST 
    // No musicplayer required
#else      
      musicPlayer.playFullFile("track001.mp3");
#endif      
      DoFlash = true;
      Serial.println("Flash!");
    }
    else {
      digitalWrite (Switch1LightPin, LOW);
      DoFlash = false;
      Serial.println("No Flash!");
    }
  }  
 if (DoFlash) Flash(); 
}

void Flash(){
  static unsigned long lastFlash = 0;
  if(millis()-lastFlash > flash){
    lastFlash = millis();
    digitalWrite(Switch1LightPin,!digitalRead(Switch1LightPin));
  }
}

boolean Switch1Released(){
  static byte lastState = HIGH;
  static unsigned long lastChange;
  static byte released = false;
  byte state = digitalRead(Switch1);
  if (lastState != state) lastChange = millis();
  if (millis() - lastChange > 30) {
     if (!state) released = true;
    }
  lastState = state;  
  if (released && state)  {
     released = false;
     return true;
  }
  return false;
}

boolean Switch5Released(){
  static byte lastState = HIGH;
  static unsigned long lastChange;
  static byte released = false;
  byte state = digitalRead(Switch5);
  if (lastState != state) lastChange = millis();
  if (millis() - lastChange > 30) {
     if (!state) released = true;
    }
  lastState = state;  
  if (released && state)  {
     released = false;
     return true;
  }
  return false;
}

Yes, the sketch on Wiki is very close - Im actually using the GRNDs directly below 52 for the LEDs, and below 53 for the switches.

The switches Im using aren't momentary push buttons, they are locking toggles actually - see this link: Push Button Locking Switch

The flashing does work BTW - its just that double-clicking of the switches to get it all to work.

There are libraries which save you the hassle of detecting these changes (and debouncing them) on foot, e. g. ezButton (https://arduinogetstarted.com/tutorials/arduino-button-library)

I know, but this is a way to show others what is behind :wink:

1 Like

Okay that explains what happens! The routines I supplied are based on simple buttons, no switches. That is the reason you have to handle them twice.

Not a big deal! Try this:

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


// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins.
// See http://arduino.cc/en/Reference/SPI "Connections"

// These are the pins used for the breakout example
#define BREAKOUT_RESET  9      // VS1053 reset pin (output)
#define BREAKOUT_CS     10     // VS1053 chip select pin (output)
#define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
// 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 breakout-example object!
  //Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
  // create shield-example object!
  Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

//define switches
const char Switch5 = 31;
const char Switch1 = 35;

//define global variables
bool pressed = false;
int dt = 500;
unsigned long flash = 800;
int CommLightPin = 28;
int Switch5LightPin = 26;
int Switch1LightPin = 30;


void setup() {
  Serial.begin(115200);
  Serial.println("Adafruit VS1053 Simple Test");
#ifdef TEST  
  // No musicplayer, no SD card required
#else
  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
  }
#endif
  // put your setup code here, to run once:

  // setup Pin Modes
  pinMode(Switch5, INPUT_PULLUP);
  pinMode(Switch1, INPUT_PULLUP);
  pinMode (CommLightPin, OUTPUT);
  pinMode (Switch5LightPin, OUTPUT);
  pinMode (Switch1LightPin, OUTPUT);

}

boolean Switch5State = false;
boolean Switch1State = false;
boolean DoFlash      = false;

void loop() {


  //read Switch5
  if(Switch5Changed()) {
    Switch5State = !Switch5State;
    if (Switch5State) {
      digitalWrite (CommLightPin, HIGH);
      digitalWrite (Switch5LightPin, HIGH);
    }
    else {
      digitalWrite (CommLightPin, LOW);
      digitalWrite (Switch5LightPin, LOW);
    }
  } 

  //read Switch1
  if (Switch1Changed()){
    Switch1State = !Switch1State;
    if (Switch1State) {
#ifdef TEST 
    // No musicplayer required
#else      
      musicPlayer.playFullFile("track001.mp3");
#endif      
      DoFlash = true;
      Serial.println("Flash!");
    }
    else {
      digitalWrite (Switch1LightPin, LOW);
      DoFlash = false;
      Serial.println("No Flash!");
    }
  }  
 if (DoFlash) Flash(); 
}

void Flash(){
  static unsigned long lastFlash = 0;
  if(millis()-lastFlash > flash){
    lastFlash = millis();
    digitalWrite(Switch1LightPin,!digitalRead(Switch1LightPin));
  }
}

boolean Switch1Changed(){
  static unsigned long lastChange = 0;
  static byte lastState = digitalRead(Switch1);
  static bool changeOk = false;
  byte state = digitalRead(Switch1);
  if (lastState != state) {
    lastState = state;
    lastChange = millis();
    changeOk = true;
  }
  if (millis()-lastChange > 30 && changeOk){
   changeOk = false;
   return true;
  } else return false;
}


boolean Switch5Changed(){
  static unsigned long lastChange = 0;
  static byte lastState = digitalRead(Switch5);
  static bool changeOk = false;
  byte state = digitalRead(Switch5);
  if (lastState != state) {
    lastState = state;
    lastChange = millis();
    changeOk = true;
  }
  if (millis()-lastChange > 30 && changeOk){
   changeOk = false;
   return true;
  } else return false;
}

https://wokwi.com/projects/335106585623790163

Yup, that did it! Many thanks!
I'm a beginner to Arduino, so please forgive my questions and ignorance. I'm trying to see the difference in the code between the momentary and SPST throw switch that I'm using in your code. I get the reading state and the flash function, but just having difficulty in the other.

And I did add the eZButton library and will try it out, thanks!

You are welcome. There is nothing bad with asking questions and honestly telling what you understood and what not...

Although I solved your problem I hope you can use the code to gain further understanding. I also learn new things on a daily base ...

You will see that there are almost twice as many solutions than developers for each problem or task... :wink: Therefore my solution is surely not " the best", but it works...

Thank you sir! I do appreciate all your efforts!

1 Like

Thanks. Just a couple other questions,

I need to add two more switches that flash (switch 2 and Switch 3), another switch that just lights an LED and plays an audio, and another switch that plays an audio when connected, and plays another when disconnected.

I can see I need to add the additional Booleans at the end, I'll also need two addition void Flashes for the flashing of the other two switches - the part that I get stuck on is in the void setup, with that additional if (DoFlash) Flash(); - I'm not sure exactly when to nest all that - initial tests causes it to just go back to flashing no matter what.

Sorry - I meant the void loop section, not the void setup.

Your question concerning "if (DoFlash) Flash()":

  • DoFlash is a boolean set to "false" when the sketch starts.
  • It toggles its state (true/false) with each change of the switch1 state.
  • If it is true the part after (DoFlash) is performed otherwise the function Flash() will be skipped.

You could copy and rename the routines and variables used for e.g. Switch1 and add them in loop() ... That will work but is not recommended as it implies multiple repetitions of code and will make debugging, readability and maintenance of the code difficult.

With two switches it was a tradeoff between doubling code or a little bit more effort for a generic solution. In the case of four switches it makes sense to (at least) create structs that take care of the switches and probably also the LEDs ...

I see - thanks! Ill keep working and learning. I do appreciate your help!

Just a matter of terminology.

There is no "void loop" section or "void setup". There are "setup()" and "loop()" functions.
:thinking:

OK, thanks. Basically everything's a function then.

question - in a sketch, there can only be a single setup() and loop() function, or can you have multiple loop() functions? (not referring to a traditional WHILE loop - more the Arduino loop() function...)

One loop function is all you get. And, fortunately, all you need.