Serval Things at the Same Time - Help

I came across this post from back in March of 2014, “Demonstration code for several things at the same time.” by Robin2. I have been able to modify the code to accomplish most of what I would like to do. Unfortunately, my programming skills are severely lacking. I used to program in C++ about 25 years ago in college. I have done zero programing since then.

This is for a Pennywise Halloween prop I have been working on. When no one is close to Pennywise there is creepy background music playing. The fog machine kicks off every few minutes as well as the strobe light for a fraction of a second. This helps draw attention to Pennywise. Once people get close and the PIR goes HIGH the background music stops, a fog machine runs, and the strobe light runs for a few seconds then turns off. Finally a couple spotlights turn on to light up Pennywise as an mp3 of Pennywise talking plays, ( the party where he asks Georgy if he would like a balloon). It really freaked some people out last year, but I think I can do a little better because the program was lacking greatly.

Hardware I am using:
Arduino Uno R3
4 Relay Module
PIR Sensor HC-SR501
DFPlayer mini

I would like to play a background MP3 track on repeat while the PIR is LOW, When the PIR goes HIGH a different MP3 track will play. This is the part I am having issues with. I have been able to get the DFPlayer to play music. However, I start playing the background mp3 track in the loop. Obviously, this keeps restarting the mp3 track over and over again.

I could time how long both mp3 tracks are and then create a separate timer function for each track. Like how Robin2 did it. Not sure if that is the best approach, thou.

Thank you for any time you can give me.
Chris

#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>

// ----CONSTANTS (won't change)
SoftwareSerial mySoftwareSerial(10, 11);
DFRobotDFPlayerMini myDFPlayer;
const int Strobe = A3; //strobe relay
const int Smoke = A1; //smoke relay
const int Spot = A2; //spot relay
const int pirSensor = 8; //PIR sensor to PIN 8

const int Strobe_Interval = 10000; // number of millisecs between Strobe lights
const int Smoke_Interval = 1000; // number of millisecs between fog blasts
const int Spot_Interval = 500; // number of millisecs between spot flashes

const int StrobeDuration = 1000; // number of millisecs that Strobe light is on
const int SmokeDuration = 1000; // number of millisecs that the fog machines is on
const int SpotDuration = 5000; // number of millisecs that the spot is on

//------- VARIABLES (will change)

byte Strobe_State = LOW;           //   LOW = off
byte Smoke_State = LOW;
byte Spot_State = LOW;

int reading; //to read PIR output

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()

unsigned long previousStrobe_Millis = 0; // will store last time the strobe was flashed
unsigned long previousSmoke_Millis = 0; // will store last time the smoke machine ran
unsigned long previousSpot_Millis = 0; // will store last time the smoke machine ran

//========

void setup() {

  Serial.begin(9600);
  Serial.println("Starting SeveralThingsAtTheSameTimeRev1.ino");  // so we know what sketch is running
  mySoftwareSerial.begin(9600);
  myDFPlayer.begin(mySoftwareSerial);
  myDFPlayer.setTimeOut(500);

  pinMode(pirSensor, INPUT);
  pinMode(Strobe, OUTPUT);
  pinMode(Smoke, OUTPUT);
  pinMode(Spot, OUTPUT);

  myDFPlayer.volume(30);
  myDFPlayer.EQ(DFPLAYER_EQ_BASS);
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
}

//=======

void loop() {

  currentMillis = millis();   // capture the latest value of millis()
  //   this is equivalent to noting the time from a clock
  //   use the same time for all LED flashes to keep them synchronized

  reading = digitalRead(pirSensor); //read PIR output

  if (reading == HIGH) { //PRI is HIGH when there is motion
    Serial.println("Motion");
    Serial.print("Strobe State = ");
    Serial.println(Strobe_State);
    Serial.print("Spot State = ");
    Serial.println(Spot_State);
    Serial.print("Smoke State = ");
    Serial.println(Smoke_State);
    Serial.print("PIR State = ");
    Serial.println(reading);
    Strobe_State = HIGH;
    Smoke_State = HIGH;
    Spot_State = HIGH;
    digitalWrite(Strobe, Strobe_State);
    digitalWrite(Spot, Spot_State);
    digitalWrite(Smoke, Smoke_State);
  } else {
    Serial.print("pirSensor is - "); //PRI is LOW when there is no motion
    Serial.println(reading);
    myDFPlayer.enableLoopAll(); //play background music
    updateStrobe_State();
    updateSpot_State();
    updateSmoke_State();
    switchState();
  }
}

//========

void updateStrobe_State() {

  if (Strobe_State == LOW) {
    if (currentMillis - previousStrobe_Millis >= Strobe_Interval) {
      Strobe_State = HIGH;
      previousStrobe_Millis += Strobe_Interval;
    }
  }
  else {
    if (currentMillis - previousStrobe_Millis >= StrobeDuration) {
      Strobe_State = LOW;
      previousStrobe_Millis += StrobeDuration;
    }
  }
}

//========

void updateSpot_State() {

  if (Spot_State == LOW) {
    if (currentMillis - previousSpot_Millis >= Spot_Interval) {
      Spot_State = HIGH;
      previousSpot_Millis += Spot_Interval;
    }
  }
  else {
    if (currentMillis - previousSpot_Millis >= SpotDuration) {
      Spot_State = LOW;
      previousSpot_Millis += SpotDuration;
    }
  }
}
//=======

void updateSmoke_State() {

  if (Smoke_State == LOW) {
    if (currentMillis - previousSmoke_Millis >= Smoke_Interval) {
      Smoke_State = HIGH;
      previousSmoke_Millis += Smoke_Interval;
    }
  }
  else {
    if (currentMillis - previousSmoke_Millis >= SmokeDuration) {
      Smoke_State = LOW;
      previousSmoke_Millis += SmokeDuration;
    }
  }
}

//========

void switchState() {
  // this is the code that actually switches things on and off

  digitalWrite(Strobe, Strobe_State);
  digitalWrite(Spot, Spot_State);
  digitalWrite(Smoke, Smoke_State);

}

//=====END

SeveralThingsAtTheSameTimeRev1.ino (6.3 KB)

More members will see your code if it is posted properly. Read the how to use this forum-please read sticky to see how to properly post code. Remove useless white space and format the code with the IDE autoformat tool (crtl-t or Tools, Auto Format) before posting code.

Thank you for your help.

chrisrc:
However, I start playing the background mp3 track in the loop. Obviously, this keeps restarting the mp3 track over and over again.

Please post a link to the documentation for the MP3 library you are using. I wonder if it has a function that tells you when a track is complete.

...R

Thank you for the reply. I have read the documentation but perhaps a I am missing something or am using the wrong library file.

The packaging for the module says - "Generic DFPlayer Mini MP3 Module" with a part number of X0020W0M3R.

On the player itself I see "MP3-TF-16P"

Not only is there no documentation for the library but there are no useful comments in the code either.

One of the examples is called ReadValues and it looks as if the function readType() can produce a value that indicates that the play has finished.

...R

Is this what you are asking for? I am sorry but I am totally new to Arduino's and am currently way over head with this program. Just trying to learn. Sorry if I am upsetting you. I am trying my best to get you what you are asking for.

DFPlayer Manual.pdf (837 KB)

chrisrc:
Is this what you are asking for?

No. I was hoping there would be documentation that explains what each of the functions in the library is for and how to use them.

I assume that the library correctly controls the hardware so there seems no reason to study the hardware documentation.

...R

I couldn't find anything that explains the library. I have been looking for that for a few days now.

Yes the hardware is working correctly I believe

Hi
I could relate the topic of this forum with my situation "Several things at the same time". I want to start tinkering with arduino but don't know from where to begin with. There are soo soo soo many things out there, it's confusing me like hell. Can someone suggest me some simple hardware to begin with, and at the same time it helps me to learn as well.

Thanks in advance

chrisrc:
I couldn't find anything that explains the library. I have been looking for that for a few days now.

It only took me a few minutes to figure that out :slight_smile:

Have you followed up what I suggested in Reply #5 - I suspect that is how you will solve your problem.

...R

Sorry for the delay in getting back to you. I have been working on the code and trying to find any information on this mp3 player library. I find programming in Arduino to be very frustrating since there is not a debugger. So I have been adding serial. Print commands all over the place and trying to sort through the outputs. I did see a debugger has been released but not for the Uno.

I started back at zero and have been playing with some sample code that came with the "MP3-TF-16P" library. I am able to play different tracks from my sd card with some sample code I have written. I am having issues with the code that is below. I have a push button using a pull up resistor that is simulating a PIR sensor. I thought this would be easier to troubleshoot then with the PIR for now.

What is happening is the mp3 track as a stuttering. The first fraction of a second of the track plays on repeat. The code keeps looping thou as it should. It's very odd to me. I don't see why this happening. I have left all my serial. Print comments in. I tried to break my code up into functions but have reverted back to basic global variables and just one function to initialize the mp3 player.

Can you see any thing wrong with this code?

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

int j = 0;
int count = 0;
int playMusic = 24; //number of loops that music takes to complete

//pusbutton variables
int LEDState=0;
int LEDPin=8;
int buttonPin=12;
int buttonNew;
int buttonOld=1;
int dt=100;
 
void setup() {
mySoftwareSerial.begin(9600);
Serial.begin(115200);

setupMP3(); //call setupMP3 function

//pushbutton
pinMode(LEDPin, OUTPUT);
pinMode(buttonPin, INPUT);
 
}
 
void loop() {

buttonNew=digitalRead(buttonPin);
              Serial.println("*************************************************************");
              Serial.println("Top of Void Loop");
              Serial.print("J = ");
                Serial.println(j);
              Serial.print("LED State = ");
                Serial.println(LEDState);
              Serial.print("ButtonNew = ");
                Serial.println(buttonNew);
              Serial.print("ButtonOld = ");
                Serial.println(buttonOld);
if(buttonOld==0 && buttonNew==1){
            Serial.println("*************************************************************");
            Serial.println("Compare button old vs new.");
            Serial.print("J = ");
              Serial.println(j);
            Serial.print("LED State = ");
              Serial.println(LEDState);
            Serial.print("ButtonNew = ");
              Serial.println(buttonNew);
            Serial.print("ButtonOld = ");
              Serial.println(buttonOld);
  if (LEDState==0){
                Serial.println("*************************************************************");
            Serial.println("LEDState == 0");
            Serial.print("LED State = ");
              Serial.println(LEDState);
            Serial.print("ButtonNew = ");
              Serial.println(buttonNew);
            Serial.print("ButtonOld = ");
              Serial.println(buttonOld);
    digitalWrite(LEDPin,HIGH);
    LEDState=1;
  }
  else{
            Serial.println("*************************************************************");
            Serial.println("LEDState ==0 Else");
            Serial.print("LED State = ");
              Serial.println(LEDState);
            Serial.print("ButtonNew = ");
              Serial.println(buttonNew);
            Serial.print("ButtonOld = ");
              Serial.println(buttonOld);
    digitalWrite(LEDPin, LOW);
    LEDState=0;
 }
}
buttonOld=buttonNew;
delay(dt); //switch bounce delay

//***********************************************************************************
//Play the first mp3
  if (LEDState == 1 && j != playMusic) {
    j = j + 1;
    myDFPlayer.play(1);  //Play the first mp3
            Serial.println("*************************************************************");
            Serial.println("MP3One");
            Serial.print("J = ");
              Serial.println(j);
            Serial.print("LED State = ");
              Serial.println(LEDState);
  }
  if (j == playMusic) {
            Serial.println("*************************************************************");
            Serial.println("MP3One - J = PlayMusic");
            Serial.print("J = ");
              Serial.println(j);
            Serial.print("LED State = ");
              Serial.println(LEDState);
    j=0; //reset counters to loop music
 }
//***********************************************************************************
//Play the second mp3
  if (LEDState == 0 && j != playMusic ) {
    j = j + 1;
    myDFPlayer.play(2);  //Play the second mp3
            Serial.println("*************************************************************");
            Serial.println("MP3Two");
            Serial.print("J = ");
              Serial.println(j);
            Serial.print("LED State = ");
              Serial.println(LEDState);
  }
  if (j == playMusic) {
            Serial.println("*************************************************************");
            Serial.println("MP3Two - J = PlayMusic");
            Serial.print("J = ");
              Serial.println(j);
            Serial.print("LED State = ");
              Serial.println(LEDState);
    j=0; //reset counters to loop music
 }
}

//****************************************************************************
void setupMP3(){
  
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true) {
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }
 Serial.println(F("DFPlayer Mini online."));
 myDFPlayer.volume(30); //Set volume value (0~30)
 myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);//Set device we use SD as default
 myDFPlayer.enableDAC();  //Enable On-chip DAC
 myDFPlayer.EQ(DFPLAYER_EQ_BASS);
      //  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
      //  myDFPlayer.EQ(DFPLAYER_EQ_POP);
      //  myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
      //  myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
      //  myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
      //  myDFPlayer.EQ(DFPLAYER_EQ_BASS);
 
 //----Read status imformation of MP3 playe----
  Serial.print("MP3 State = ");
    Serial.println(myDFPlayer.readState()); //read mp3 state
  Serial.print("Current Volume = ");
    Serial.println(myDFPlayer.readVolume()); //read current volume
  Serial.print("EQ Setting = ");
    Serial.println(myDFPlayer.readEQ()); //read EQ setting
  Serial.print("Number of files = ");
    Serial.println(myDFPlayer.readFileCounts()); //read all file counts in SD card
  Serial.print("Current file number = ");
    Serial.println(myDFPlayer.readCurrentFileNumber()); //read current play file number
  Serial.print("File Count in folder = ");
    Serial.println(myDFPlayer.readFileCountsInFolder(1)); //read fill counts in folder SD:/01      
}

chrisrc:
Can you see any thing wrong with this code?

I'm all in favour of using Serial.print() statements for debugging but you have so many that they obscure the code.

Also please use the AutoFormat tool to indent your code consistently. It makes it much easier to see the blocks of code.

I have no idea what the variable playMusic is intended for.

I see no evidence of you using the suggestion I made in Reply #5. As I said then, I reckon that will solve your problem but I don't have your hardware so I can't try it.

...R

LOL I know. Robin2 I had way too many print statements in there and it was a little confusing for me as well. I have removed a large number of them. I have also cleaned up the code significantly. I went back to reply #5 and started playing around with your suggestion. That function you suggested, readType() did not seem to work.

I found another post with a very similar problems to what I was dealing with. Turns out there is a much better library to use. DFPPlayerMini_Fast.h has an isPlaying() function and that seems to have solved the play back issue. Thank you to user Power_Broker for the great library.

I have one issue left to solve. If track one is playing and you press the button then track one should stop and track two should start right away. Right now track one have to complete before track two will start. I think this is going to require some logical comparison between the variables ButtonOld and Button New or a change in LEDState. I just can's see the statement yet.

#include <Arduino.h>
#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFPlayerMini_Fast myDFPlayer;
void printDetail(uint8_t type, int value);

//pusbutton variables
int LEDState = 0;
int LEDPin = 8;
int buttonPin = 12;
int buttonNew;
int buttonOld = 1;
int dt = 100;

void setup() {
  mySoftwareSerial.begin(9600);
  Serial.begin(115200);

  setupMP3(); //call setupMP3 function

  //pushbutton
  pinMode(LEDPin, OUTPUT);
  pinMode(buttonPin, INPUT);

}
void loop() {

  buttonNew = digitalRead(buttonPin);

  if (buttonOld == 0 && buttonNew == 1) {
    if (LEDState == 0) {
      LEDState = 1;
    }
    else {
      LEDState = 0;
    }
  }
  buttonOld = buttonNew;
  delay(dt); //switch bounce delay

  //***********************************************************************************
  //Play the first mp3
  if (LEDState == 1 && myDFPlayer.isPlaying() == false) {
    myDFPlayer.play(1);  //Play the first mp3
  }
  //***********************************************************************************
  //Play the second mp3
  if (LEDState == 0 && myDFPlayer.isPlaying() == false) {
    myDFPlayer.play(2);  //Play the second mp3
  }
}
//****************************************************************************
void setupMP3() {

  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true) {
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }
  Serial.println(F("DFPlayer Mini online."));
  myDFPlayer.volume(30); //Set volume value (0~30)
  myDFPlayer.EQSelect(5);
  //EQ_NORMAL = 0;
  //EQ_POP = 1;
  //EQ_ROCK = 2;
  //EQ_JAZZ = 3;
  //EQ_CLASSIC = 4;
  //EQ_BASE = 5;

  //----Read status imformation of MP3 playe----
  Serial.print("Current Volume = ");
  Serial.println(myDFPlayer.currentVolume()); //read current volume
  Serial.print("EQ Setting = ");
  Serial.println(myDFPlayer.currentEQ()); //read EQ setting
  Serial.print("Number of files = ");
  Serial.println(myDFPlayer.numSdTracks()); //read all file counts in SD card
  Serial.print("Current file number = ");
  Serial.println(myDFPlayer.currentSdTrack()); //read current play file number
}

I'm not familiar with your library, but I do notice a stop function in it :wink:

chrisrc:
That function you suggested, readType() did not seem to work.

Please post the program in which you tried it.

Did you try the code from the example without any changes?

...R

Hey WildBill,

Yes I see the stop function as well. I just don't see the if statement needed to call the stop function. I have been staring at this code for so long I might be blind and just not seeing it.

I think it needs to be something like this -

  • If the LEDState changes then.... (this is the part I am stuck at)
  • run the stop command
  • examine the LEDState and continue to the next if statement.

I understand that library is non blocking.

What happens if you change your conditional statements to leave out the .isPlaying()== false.

//Play the first mp3
  //if (LEDState == 1 && myDFPlayer.isPlaying() == false) {
     if (LEDState == 1){
    myDFPlayer.play(1);  //Play the first mp3
  }
  //***********************************************************************************
  //Play the second mp3
  //if (LEDState == 0 && myDFPlayer.isPlaying() == false) {
     if (LEDState == 0){
    myDFPlayer.play(2);  //Play the second mp3
  }

If you omit that .isPlaying()== false statement then the mp3 player starts the track at every pass of the loop. So you end up with a small little fraction of a second of the mp3 file playing. It never completes the full track.

I think it needs to be something like this -

If the LEDState changes then.... (this is the part I am stuck at)
run the stop command
examine the LEDState and continue to the next if statement.

Does this do it? It puts the track management in the state change detection.

#include <Arduino.h>
#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFPlayerMini_Fast myDFPlayer;
void printDetail(uint8_t type, int value);

//pusbutton variables
int LEDState = 0;
int LEDPin = 8;
int buttonPin = 12;
int buttonNew;
int buttonOld = 1;
int dt = 100;

void setup() {
  mySoftwareSerial.begin(9600);
  Serial.begin(115200);

  setupMP3(); //call setupMP3 function

  //pushbutton
  pinMode(LEDPin, OUTPUT);
  pinMode(buttonPin, INPUT);

}
void loop() {

  buttonNew = digitalRead(buttonPin);

  if (buttonOld == 0 && buttonNew == 1) {
    if (LEDState == 0) {
      LEDState = 1;
      //Serial.println(LEDState);
      myDFPlayer.stop();
      myDFPlayer.play(LEDState);
    }
    else {
      LEDState = 0;
      //Serial.println(LEDState);
      myDFPlayer.stop();
      myDFPlayer.play(LEDState);
    }
  }
  buttonOld = buttonNew;
  delay(dt); //switch bounce delay
  
/*
    //Play the first mp3
    if (LEDState == 1 && myDFPlayer.isPlaying() == false) {
      myDFPlayer.play(1);  //Play the first mp3
    }
    //***********************************************************************************
    //Play the second mp3
    if (LEDState == 0 && myDFPlayer.isPlaying() == false) {
      myDFPlayer.play(2);  //Play the second mp3
    }
  */
}
//****************************************************************************


  void setupMP3() {

  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true) {
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }
  Serial.println(F("DFPlayer Mini online."));
  myDFPlayer.volume(30); //Set volume value (0~30)
  myDFPlayer.EQSelect(5);
  //EQ_NORMAL = 0;
  //EQ_POP = 1;
  //EQ_ROCK = 2;
  //EQ_JAZZ = 3;
  //EQ_CLASSIC = 4;
  //EQ_BASE = 5;

  //----Read status imformation of MP3 playe----
  Serial.print("Current Volume = ");
  Serial.println(myDFPlayer.currentVolume()); //read current volume
  Serial.print("EQ Setting = ");
  Serial.println(myDFPlayer.currentEQ()); //read EQ setting
  Serial.print("Number of files = ");
  Serial.println(myDFPlayer.numSdTracks()); //read all file counts in SD card
  Serial.print("Current file number = ");
  Serial.println(myDFPlayer.currentSdTrack()); //read current play file number
  }