Help with fading lights and music for alarm clock

Hi everyone,

I am trying to build a wake up light (an alarm clock with a LED strip) using:

  1. Arduino mega
  2. a tft touch screen
  3. a real tim clock
  4. mini dfp player
  5. a LED strip

I am trying to do this project one step at a time and now I am trying to get the alarm function to work. For the alarm function I need the LED strip and the mp3 volume to fade in.
As I want to be able to switch of the alarm during this function I am building it without using delays. So I am using the millis() functionalities.

I have two problems:
The fading of the volume does not work, there is no sound coming out of the MP3 player anymore.
The LED fading stopped working once I implemented the volume fade.

Any help is much appreciated!
Hereby the code:

#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h> // MP3 library

SoftwareSerial mySoftwareSerial(47, 45); // RX, TX  Define so the MP3 can write back to the computer
DFRobotDFPlayerMini myDFPlayer;

//MP3
//Define Mp3
# define startByte 0x7E
# define endByte 0xEF
# define versionByte 0xFF
# define dataLength 0x06
# define infoReq 0x01
# define Acknowledge 0x00

// define directions for LED fade
#define UP 0

// declarations for the volume fade
unsigned long previousFadeMillis_volume;
byte volumeIncrement = 1;
byte volumeDirection = UP;
int volumeInterval = 100;
int volumeValue = 10;
const int maxvolume = 20;

//declarations for the LED fade

const byte pwmLED = 46;

// constants for min and max PWM
const int minPWM = 0;
const int maxPWM = 180;

// State Variable for Fade Direction
byte fadeDirection = UP;

// Global Fade Value
// but be bigger than byte and signed, for rollover
int fadeValue = 0;

// How smooth to fade?
byte fadeIncrement = 1;

// millis() timing Variable, just for fading
unsigned long previousFadeMillis;

// How fast to increment?
int fadeInterval = 100;

void setup() {
  // put pwmLED into known state (off)
  analogWrite(pwmLED, fadeValue);


  //MP3

  mySoftwareSerial.begin(9600);
  Serial.begin(9600);
  //   Serial.begin(115200);

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(mySoftwareSerial, false)) {  //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);
  }
  Serial.println(F("DFPlayer Mini online."));

  myDFPlayer.setTimeOut(500); //Set serial communication time out 500ms

  //----Set volume----
  myDFPlayer.volume(volumeValue);  //Set volume value (0~30).

  //----Set different EQ----
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);

  //----Set device we use SD as default----
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

}

void loop() {
  // get the current time, for this time around loop
  // all millis() timer checks will use this time stamp
  unsigned long currentMillis = millis();

  playAlarm(currentMillis);
  myDFPlayer.start();

}


void playAlarm(unsigned long thisMillis)
{
  // LED fade
  // is it time to update yet?
  // if not, nothing happens
  if (thisMillis - previousFadeMillis >= fadeInterval) {
    // yup, it's time!
    if (fadeDirection == UP) {
      fadeValue = fadeValue + fadeIncrement;
      if (fadeValue >= maxPWM) {
        // At max, limit and change direction
        fadeValue = maxPWM;
      }
    }
  }
  // Volume fade
  if (thisMillis -  previousFadeMillis_volume >= volumeInterval) {
    // yup, it's time!
    if (volumeDirection == UP) {
      volumeValue =  volumeValue + volumeIncrement;
      if (volumeValue >= maxvolume) {
        // At max, limit and change direction
        volumeValue = maxvolume;
      }
    }
  }
  // Only need to update when it changes
  analogWrite(pwmLED, fadeValue);
  myDFPlayer.volume(volumeValue);

  // reset millis for the next iteration (fade timer only)
  previousFadeMillis = thisMillis;
  previousFadeMillis_volume = thisMillis;

}

Hi and welcome to the forum.

As you can see, the forum has made a mess of your code. Indentation is lost and formatting changes at random. This is because you did not use code tags. Please edit your first post and fix that. The easiest way is to click “Tools–>Auto format” in the Arduino IDE, then click “Edit–>Copy to forum” and paste into your post.

Question: why are you using software serial? Mega has several hardware serial ports available, and they should always be used in preference to software serial.

Hello,
take a look into your sketch and see when do you reload the millis() into the timer functions for previousFadeMillis and previousFadeMillis_volume. I gues that this causes your malfunction of you sketch.

Thank you for the reply!
I edited my post. This looks much better :slight_smile:

As an answer to your question:
I used the code I found in a tutorial and on github, which both use software serial and pins 10 and 11.

As the pins 10 and 11 are taken by the touch screen in my project, my guess was to use PWM pins. but as I discover now, these are not the same as tx and rx pins and 47 isn’t even a PWM pin.
But even with this the mp3 in itself to works quite well with simple play, pause, next and back commands. The volume control is my struggle. It did work with a delay function like this:

  myDFPlayer.play(1);
  brightness = 30;
  analogWrite(led, brightness);
  delay(5000);
  myDFPlayer.volume(6);
  brightness = 60;
  analogWrite(led, brightness);
  delay(5000);
  myDFPlayer.volume(8);
  brightness = 90;
  analogWrite(led, brightness);
  delay(5000);
  myDFPlayer.volume(10);
  brightness = 120;
  analogWrite(led, brightness);
  delay(5000);
  myDFPlayer.volume(15);
  delay(5000);
  brightness = 5;
  analogWrite(led, brightness);
  myDFPlayer.volume(2);

But I think this is not the way to go with building this, as it is quite an ugly long code and there are a lot of delays in there, which I guess will not allow to build a snooze / off button.

If you suggest to use other ports I would be happy to try it out! However, the tft touch screen shield blocks ports 0-13 and a0-a5.

1 Like

Thanks for the reply!
I changed the location, now the fading of the light works again :+1:
The fading of the volume still doesn’t unfortunately.

#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h> // MP3 library

SoftwareSerial mySoftwareSerial(47, 45); // RX, TX  Define so the MP3 can write back to the computer
DFRobotDFPlayerMini myDFPlayer;

//MP3
//Define Mp3
# define startByte 0x7E
# define endByte 0xEF
# define versionByte 0xFF
# define dataLength 0x06
# define infoReq 0x01
# define Acknowledge 0x00

// define directions for LED fade
#define UP 0

// declarations for the volume fade
unsigned long previousFadeMillis_volume;
byte volumeIncrement = 1;
byte volumeDirection = UP;
int volumeInterval = 100;
int volumeValue = 10;
const int maxvolume = 20;

//declarations for the LED fade

const byte pwmLED = 46;

// constants for min and max PWM
const int minPWM = 0;
const int maxPWM = 180;

// State Variable for Fade Direction
byte fadeDirection = UP;

// Global Fade Value
// but be bigger than byte and signed, for rollover
int fadeValue = 0;

// How smooth to fade?
byte fadeIncrement = 1;

// millis() timing Variable, just for fading
unsigned long previousFadeMillis;

// How fast to increment?
int fadeInterval = 1000;

void setup() {
  // put pwmLED into known state (off)
  analogWrite(pwmLED, fadeValue);


  //MP3

  mySoftwareSerial.begin(9600);
  Serial.begin(9600);
  //   Serial.begin(115200);

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  if (!myDFPlayer.begin(mySoftwareSerial, false)) {  //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);
  }
  Serial.println(F("DFPlayer Mini online."));

  myDFPlayer.setTimeOut(500); //Set serial communication time out 500ms

  //----Set volume----
  myDFPlayer.volume(volumeValue);  //Set volume value (0~30).

  //----Set different EQ----
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);

  //----Set device we use SD as default----
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

}

void loop() {
  // get the current time, for this time around loop
  // all millis() timer checks will use this time stamp
  unsigned long currentMillis = millis();

  playAlarm(currentMillis);
  myDFPlayer.start();

}


void playAlarm(unsigned long thisMillis)
{
  // LED fade
  // is it time to update yet?
  // if not, nothing happens
  if (thisMillis - previousFadeMillis >= fadeInterval) {
    // yup, it's time!
    if (fadeDirection == UP) {
      fadeValue = fadeValue + fadeIncrement;
      if (fadeValue >= maxPWM) {
        // At max, limit and change direction
        fadeValue = maxPWM;
      }
    }
    // Only need to update when it changes
    analogWrite(pwmLED, fadeValue);
    // reset millis for the next iteration (fade timer only)
    previousFadeMillis = thisMillis;
  }
  // Volume fade
  if (thisMillis -  previousFadeMillis_volume >= volumeInterval) {
    // yup, it's time!
    if (volumeDirection == UP) {
      volumeValue =  volumeValue + volumeIncrement;
      if (volumeValue >= maxvolume) {
        // At max, limit and change direction
        volumeValue = maxvolume;
      }
    }

    // Only need to update when it changes
    myDFPlayer.volume(volumeValue);

    // reset millis for the next iteration (fade timer only)
    previousFadeMillis_volume = thisMillis;

  }
}
myDFPlayer.start();

I’m not sure why you have this in loop(), I suggest you try removing it.

I suggest you find out if any hardware serial ports are not blocked and use one of those.

Okay, since last update the code stopped working totally. So I took a step back and try to get the DFplayer working again. I noticed that I can not get it to work on other pins than 11 and 10 using this code:

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

// Use pins 2 and 3 to communicate with DFPlayer Mini

static const uint8_t PIN_MP3_TX = 11; // Connects to module's TX GEEL
static const uint8_t PIN_MP3_RX = 10; // Connects to module's RX GROEN

SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);

// Create the Player object
DFRobotDFPlayerMini player;

void setup() {
  // Init USB serial port for debugging
  Serial.begin(9600);
  // Init serial port for DFPlayer Mini
  softwareSerial.begin(9600);

  // Start communication with DFPlayer Mini
  if (player.begin(softwareSerial)) {
    Serial.println("OK");

    // Set volume to maximum (0 to 30).
    player.volume(15);
    // Play the first track
    player.play(2);

  } else {
    Serial.println("Connecting to DFPlayer Mini failed!");
  }
}

void loop() {
}

However, pins 10 and 11 are not available in my project as the touch screen uses these pins. Do you have any other pins I could try on my arduino mega ? And how would that work with hardware serial ports? Can I use the same code? All the examples I found use softwareSerial and software serial pins.
Thanks for the help!

Find a pinout diagram for the mega and find if there is a hardware serial port that is not blocked by your touchscreen shield. If so, use that port. There will be some changes to the sketch, but they will not be difficult.

I have 3 pairs of hardware serials available, pins 14 - 19.
If I understand correctly, these pins are optimized for communication with other hardware devices, while the software.serial simulates this?
Am I right that I should only change “softwareSerial” into “Serial”? Or does this has more implications for the code?

The serial port that communicates with the serial monitor on your pc is called "Serial". The other serial ports are called "Serial1", "Serial2" and so on. To use one of those extra ports to communicate with the MP3 player, you can remove these lines

#include <SoftwareSerial.h>

SoftwareSerial mySoftwareSerial(47, 45); // RX, TX  Define so the MP3 can write back to the computer

and replace every occurrence of "mySoftwareSerial" with "SerialN" where "N" is the serial port you have chosen to use.

1 Like

Yes, that works! Great :slight_smile:
Thanks a lot.
I also got the fading to work, but there is a strange problem.
Here is the code:

#include <DFRobotDFPlayerMini.h>

// Create the Player object
DFRobotDFPlayerMini player;

unsigned long previousFadeMillis_volume;
byte volumeIncrement = 1;
int volumeInterval = 500;
int volumeValue = 5;
const int maxvolume = 20;

void setup() {
  // Init USB serial port for debugging
  Serial.begin(9600);
  // Init serial port for DFPlayer Mini
  Serial1.begin(9600);

  // Start communication with DFPlayer Mini
  if (player.begin(Serial1)) {
    Serial.println("OK");

    //Start playing the MP3
    player.play(1);

  } else {
    Serial.println("Connecting to DFPlayer Mini failed!");
  }

}

void loop() {
  unsigned long currentMillis = millis();
  playAlarm(currentMillis);
  Serial.println(volumeValue);
}

void playAlarm(unsigned long thisMillis)
{
  if (thisMillis -  previousFadeMillis_volume >= volumeInterval) {
    // yup, it's time!
    volumeValue =  volumeValue + volumeIncrement;
    if (volumeValue >= maxvolume) {
      // At max, limit
      volumeValue = maxvolume;
    }
  }
  // Only need to update when it changes
  player.volume(volumeValue);

  // reset millis for the next iteration (fade timer only)
  previousFadeMillis_volume = thisMillis;

}

This code seems to work fine.
The problem occurs when I enlarge the volumeInterval to more than 500. Then the fading stops working at all.
Do you have any idea why this happens?

Edit: I changed volumeIncrement to volumeInterval.

It seems a strange question. Either I don't understand the question, of you asked the wrong question. But it sounds like you asked "how many times can I add 500 to 5 before it becomes larger than 20?". Obviously the answer is "one time", which would result in a very sudden "fade".

My mistake, I am sorry. I meant that the volumeInterval cannot be changed into something higher than 500 ms. I will edit this in my previous reply.

I should have guessed that was what you meant, question makes sense now.

Try changing volumeInterval to unsigned long instead of int.

EDIT: Ah, you have a } in the wrong place!

  // Only need to update when it changes

But it's getting updated even when it hasn't changed, because of that misplaced }

1 Like

That wrong placed } was indeed the problem. Thanks again!
Do you have a tip how I can avoid such an error?

Hereby the updated code:

#include <DFRobotDFPlayerMini.h>

// Create the Player object
DFRobotDFPlayerMini player;

unsigned long previousFadeMillis_volume;
byte volumeIncrement = 1;
int volumeInterval = 5000;
int volumeValue = 5;
const int maxvolume = 20;

void setup() {
  // Init USB serial port for debugging
  Serial.begin(9600);
  // Init serial port for DFPlayer Mini
  Serial1.begin(9600);

  // Start communication with DFPlayer Mini
  if (player.begin(Serial1)) {
    Serial.println("OK");

    //Start playing the MP3
    player.volume(volumeValue);
    player.play(1);

  } else {
    Serial.println("Connecting to DFPlayer Mini failed!");
  }

}

void loop() {
  unsigned long currentMillis = millis();
  playAlarm(currentMillis);
  Serial.println(volumeValue);
}

void playAlarm(unsigned long thisMillis)
{
  if (thisMillis -  previousFadeMillis_volume >= volumeInterval) {
    // yup, it's time!
    volumeValue =  volumeValue + volumeIncrement;
    if (volumeValue >= maxvolume) {
      // At max, limit
      volumeValue = maxvolume;
    }
    // Only need to update when it changes
    player.volume(volumeValue);


    // reset millis for the next iteration (fade timer only)
    previousFadeMillis_volume = thisMillis;
  }
}

My next step will be to combine the mp3 code with the LED. I will keep you posted..

All I can suggest is to pay attention to indentation. Code that should always be executed together should be at the same level of indentation. Use Auto-Format to keep your indentation correct. You seem to be doing that.

You will have more dimming/fading levels with the led (255) than with the MP3 (30, but you might not want to use all of them). So I suggest you change the code above to control timing the dimming of the LEDs, then use map() function to calculate the MP3 volume from the led dimming level. That should help keep things simpler than having two independant pieces of code to fade LEDs separately from MP3 and then having to synchronise them.