triggering sound and led in response to LDR

Hey guys, so this is a millis question.

I've run through the great tutorials on here but am still struggling to get my code to work. I'm basically trying to use an LDR as an on off switch effectively so that when it reads over 800 on the serial monitor, it triggers an LED and plays the full length of an MP3 I have loaded on the DFmini player module.

I currently do trigger the LED and sound but it runs in one continuous loop from reset and im not sure why.

I'm not sure currently how to set an amount of time to allow the mp3 to play without using delay, i need to to play for roughly 3 seconds.

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

float b;

const int ledPin = 3;
const int ledpingreen = 5;
const int switchpin = 6;
const int LDR = A5;

int LDRValue = 0; // variable to store the value coming from the sensor
int prev_LDRValue = 0; // variable to store the previous state of the sensor

long startOnLDR = 0; // The Last time that input was recieved



//mp3 stuff

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

void setup()                  
{
  mySoftwareSerial.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)) {  //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);                                                                             //
  }
  
  {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode (ledPin, OUTPUT); //red LED
pinMode (ledpingreen, OUTPUT); //green LED
}
  
  Serial.println(F("DFPlayer Mini online."));
  
  myDFPlayer.setTimeOut(8000); //Set serial communictaion time out 500ms
  
  //----Set volume----
  myDFPlayer.volume(20);  //Set volume value (0~30).
  
  //----Set different EQ----
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);

  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

  
  //----Read imformation----
  Serial.println(myDFPlayer.readState()); //read mp3 state
  Serial.println(myDFPlayer.readVolume()); //read current volume
  Serial.println(myDFPlayer.readEQ()); //read EQ setting
  Serial.println(myDFPlayer.readFileCounts()); //read all file counts in SD card
  Serial.println(myDFPlayer.readCurrentFileNumber()); //read current play file number
  Serial.println(myDFPlayer.readFileCountsInFolder(3)); //read file counts in folder SD:/03
}

void loop(){

LDRValue = analogRead(LDR); // read the value from the sensor
Serial.println(LDRValue); //prints the values coming from the sensor on the screen

if (prev_LDRValue<=800 && LDRValue>800){// New Code to start Timing
startOnLDR=millis();// Start the Timer
  prev_LDRValue=LDRValue;
}

if (millis()>=800){
  
  digitalWrite(5,HIGH);

myDFPlayer.play (3);

}else{
 digitalWrite (5 , LOW);  
}

  }

any help would be greatly appreciated. Just a nudge in the right direction would be top.

while(true);
You'll never get past this!

This whole block is confusing

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);                                                                             //
}

{
    // put your setup code here, to run once:
    Serial.begin(9600);
    pinMode (ledPin, OUTPUT); //red LED
    pinMode (ledpingreen, OUTPUT); //green LED
}

DKWatson:
while(true);
You'll never get past this!

what do you mean? Sorry Im a bit confused with what your referring too.

That is just the inbuilt code for the mp3 module i'm using, it came with the library so not directly involved with the main body of the code.

if (millis() >= 800)
{
  digitalWrite(5,HIGH);
  myDFPlayer.play (3);
}
else
{
 digitalWrite (5 , LOW);  
}

millis() will be always greater than 800 after 800 milli seconds you powered your arduino.

'true' is a defined boolean equal (numerically) to one. while(true); is an infinite loop. Normally when used, it would be like this;

bool a = true;
while(a == true)
{
  do something here
  make a test here - if(something else) a = false;
}

The way that code is written, once you enter the if (!myDFPlayer.begin(mySoftwareSerial)) test, you'll never get out without a hard reset.

pranghead:
what do you mean? Sorry Im a bit confused with what your referring too.

That is just the inbuilt code for the mp3 module i'm using, it came with the library so not directly involved with the main body of the code.

while(true); is an infinte loop.

 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);                                                                             //
  }

I think the whole idea of this piece of code is to prevent further execution until communication with DFPlayer is established.

DKWatson:
'true' is a defined boolean equal (numerically) to one. while(true); is an infinite loop. Normally when used, it would be like this;

bool a = true;

while(a == true)
{
  do something here
  make a test here - if(something else) a = false;
}



The way that code is written, once you enter the if (!myDFPlayer.begin(mySoftwareSerial)) test, you'll never get out without a hard reset.

This bit of code has worked in previous projects so I dont think its the issue

Anyhow, back to your timing issue, you start the timer by setting startOnLDR=millis(); and then never test it against the elapsing time. If you want to run for three seconds (=3000ms) then test

if((mills() - startOnLDR) >= 3000)

and implement code to stop whatever you were doing. The test will repeatedly fail until 3000ms (or more) has elapsed.

pranghead:
This bit of code has worked in previous projects so I dont think its the issue

Likely not as it would only be an issue if the SD card was not inserted/connected. Still, it's bad code unless that is its purpose.

DKWatson:
Anyhow, back to your timing issue, you start the timer by setting startOnLDR=millis(); and then never test it against the elapsing time. If you want to run for three seconds (=3000ms) then test

if((mills() - startOnLDR) >= 3000)

and implement code to stop whatever you were doing. The test will repeatedly fail until 3000ms (or more) has elapsed.

ok cool, i understand that i think. I need to only trigger this in relation to the analogue read im gathering from the LDR, do I just put that in as something like this...

b=analogRead(A5);
b=b*5/1023;

if(b>=2.0&&b<=2.3)[code]

The purpose of that code block is:
If "myDFPlayer.begin" fails, then stop the whole show.

Sort of except analogRead returns an integer and your comparing floats, try

b = analogRead(A5);
float c = (float)b * 5 / 1023;
if((c >= 2.0) && (c <= 2.3));

It's important to cast at least one R value as a float in the calculation. When the compiler performs its math it will use register(s) or stack sufficient enough only to accommodate the largest type on the right hand side of the equation. If you simply went float c = b * 5 / 1023, everything on the right hand side is still an integer so the result will be an integer, regardless of the type of the L value.

DKWatson:
Sort of except analogRead returns an integer and your comparing floats, try

b = analogRead(A5);

float c = (float)b * 5 / 1023;
if((c >= 2.0) && (c <= 2.3));



It's important to cast at least one R value as a float in the calculation. When the compiler performs its math it will use register(s) or stack sufficient enough only to accommodate the largest type on the right hand side of the equation. If you simply went float c = b * 5 / 1023, everything on the right hand side is still an integer so the result will be an integer, regardless of the type of the L value.

Why bother scaling the output of the analogRead() into a range of float values just to test if it's within some limits? Instead, just scale the limits of your comparison to work with the (0-1023) range produced by analogRead(). That's a static operation that can be done once at compile-time, much better than a run-time operation that's computed for EVERY comparison.

gfvalvo:
Why bother scaling the output of the analogRead() into a range of float values just to test if it's within some limits? Instead, just scale the limits of your comparison to work with the (0-1023) range produced by analogRead(). That's a static operation that can be done once at compile-time, much better than a run-time operation that's computed for EVERY comparison.

+1

Still, it's bad code unless that is its purpose.

That IS its purpose, but it would be far better to include a comment in the code that says that.

if(!myDFPlayer.begin(mySyupidNameForASoftwareSerialInstance))
{
    // Useless comments on the ends of these line removed. Some people...
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));

    // Do nothing until the wiring problem is fixed or an SD card is inserted
    while(true);
}

so... Im still struggling with this. really struggling to understand how to use millis to get an mp3 file to play once and then wait for further input, such as the LDR picking up a change in light, to carry on and carry out another procedure. How do you get something to rely on one thing finishing to start another???

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

float b;

const int ledPin = 3;
const int ledpingreen = 5;
const int switchpin = 6;
const int LDR = A5;

int LDRValue = 0; // variable to store the value coming from the sensor
int prev_LDRValue = 0; // variable to store the previous state of the sensor

long startOnLDR = 0; // The Last time that input was recieved

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




//mp3 stuff

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

void setup()                  
{
  mySoftwareSerial.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)) {  //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);                                                                             //
  }
  
  {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode (ledPin, OUTPUT); //red LED
pinMode (ledpingreen, OUTPUT); //green LED
}
  
  Serial.println(F("DFPlayer Mini online."));
  
  myDFPlayer.setTimeOut(8000); //Set serial communictaion time out 500ms
  
  //----Set volume----
  myDFPlayer.volume(20);  //Set volume value (0~30).
  
  //----Set different EQ----
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);

  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

  
  //----Read imformation----
  Serial.println(myDFPlayer.readState()); //read mp3 state
  Serial.println(myDFPlayer.readVolume()); //read current volume
  Serial.println(myDFPlayer.readEQ()); //read EQ setting
  Serial.println(myDFPlayer.readFileCounts()); //read all file counts in SD card
  Serial.println(myDFPlayer.readCurrentFileNumber()); //read current play file number
  Serial.println(myDFPlayer.readFileCountsInFolder(3)); //read file counts in folder SD:/03
}

void loop(){

currentMillis = millis(); 

b=analogRead(A5);
b=b*5/1023;

Serial.println(b); //prints the values coming from the sensor on the screen

if(b>=4.0&&b<=5.00)

{digitalWrite(5,HIGH);

myDFPlayer.play (1); 

delay (500);

}

else{
 digitalWrite (5 , LOW);  
 digitalWrite (3, HIGH); 
}

while(digitalRead(3) == HIGH)
{ myDFPlayer.play (3);
delay (100); }

  }

currently the mp3's just play in a loop. I want to trigger a second mp3 to play once when the LDR is uncovered and then when then wait for the LDR to be covered again to reset. Any help would be greatly appreciated

I want to trigger a second mp3 to play once when the LDR is uncovered and then when then wait for the LDR to be covered again to reset.

You need to look at the state change detection example. While that specifically refers to digital state changes associated with switches (from pressed to released or from released to pressed), it doesn't take much imagination to extend it to analog values - the value is above the threshold this time but was not last time or the value is below the threshold this time but was not the last time or the value.

You want to trigger the player ONLY when the state changes. As it is now, you are trigger the player when the value IS above the threshold or IS below the threshold, rather than when the values GOES ABOVE or GOES BELOW the threshold.

PaulS:
You need to look at the state change detection example. While that specifically refers to digital state changes associated with switches (from pressed to released or from released to pressed), it doesn't take much imagination to extend it to analog values - the value is above the threshold this time but was not last time or the value is below the threshold this time but was not the last time or the value.

You want to trigger the player ONLY when the state changes. As it is now, you are trigger the player when the value IS above the threshold or IS below the threshold, rather than when the values GOES ABOVE or GOES BELOW the threshold.

thanks paul thats a really good insight, ill have a look at that now and try and wrap my skull around it