Light Screamer Project (HELP NEEDED)

I’m basically trying to make the piezo buzzer scream when there’s light and play music when it’s dark. To do so, I used a photoresistor which decreases in resistance with more light. I’m trying to make the code so that when there is light it screams once and when there is darkness it plays music once. I also want it to stop the music and quickly scream once there is light.
The problem with my code is that it screams over and over again and the music doesn’t stop. Below is my code; it would be great if someone gave me an advice to correct it. Thanks.

/* 
 * The calculation of the tones is made following the mathematical
 * operation:
 * timeHigh = period / 2 = 1 / (2 * toneFrequency)
 * where the different tones are described as in the table:
 * note   frequency   period   timeHigh
 * c    261 Hz    3830    1915 
 * d   294 Hz   3400   1700 
 * e   329  Hz  3038  1519 
 * f 349 Hz 2864 1432 
 * g 392 Hz 2550 1275 
 * a 440 Hz 2272 1136 
 * b 493 Hz 2028 1014
 */
 
 int speakerPin = 2;                                             // pin to use to drive speaker 
 char names[] = {'c','d','e','f','g','a','b'};                    // List of notes we want to be able to play
 int rangeOfNotes = 8;                                            
 int tones[] ={1915, 1700, 1519, 1432, 1275, 1136, 1014, 956};
 int length = 42;                                           
 char notes[] = "ccggaagffeeddcggffeedggffeedccggaagffeeddc ";    

 double beats[] = {1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4}; 
 int tempo = 300; 
 
 int lightSensor = 5;     //Analog pin Light Resistor is connected to
 int darknessThresh = 500;
 

void setup()
{
  pinMode(speakerPin,OUTPUT);
  Serial.begin(9600);
}

void Scream()
{
  digitalWrite(speakerPin, HIGH);
  delay(1500);
  digitalWrite(speakerPin,LOW);
  delay(1000);
}

 void playNote(char note, int duration)                         //plays the note "note" for the time "duration"
 {  
                                                                //play the tone corresponding to the note name
   for (int i = 0; i < rangeOfNotes; i++)
   {
   if (names[i] == note){
   playTone(tones[i], duration);
   }
   }
 }
   
 
 void playTone(int tone, int duration)
 {
   
   for (long i = 0; i < duration *1000L; i += tone * 2)     
   {
   digitalWrite(speakerPin, HIGH);
   delayMicroseconds(tone);
   digitalWrite(speakerPin, LOW);
   delayMicroseconds(tone);
   }
   
 }
 
void Sing()
{
  
   for (int i = 0; i < length; i++)                                
   { 
       if (notes[i] == ' ')                                        
       {
         delay(beats[i] * tempo);                            
       } 
       else                                                      
       {playNote(notes[i], beats[i] * tempo);} 
    
       delay(tempo/2);                                            
   }
}

void loop()
{
  int lightLevel = analogRead(lightSensor);   
  Serial.print("Light Level = ");             
  Serial.println(lightLevel); 
  if(lightLevel < darknessThresh)
  {
    Scream(); 
  }

  if(lightLevel > darknessThresh)
  {
   Sing();
  }
}

Hi John_Carl,

Any time now, someone is going to see the delay() functions in your sketch and say "blink without delay". But before you rip everything up to achieve that, there may be less disruptive approaches.

First a question. How does that Scream() function make a scream sound? Looks to me like it should just make a click every second or so.

As for screaming once or playing the tune once, you need to detect when the light level changes from light to dark or vice versa, not just whether its light or dark at any instant. To do this you need a second variable to record the previous light reading. Then when you take a new light reading, you can then test that the old reading was below and the new reading is above. Or vice versa. When that happens, you update the old light reading and then scream/sing.

I assume the threshold you have chosen means there it little chance of the light level hovering around the threshold level for long periods, i.e. it is always either well above or well below the threshold?

Paul

I think I got what you want but I am not sure if there is a mistake since I could not really test it.
Tell me if it works or if you have any questions :slight_smile:

btw do you want the music or scream when it is dark?
From your code it looks like you want the scream when it is dark because lightLevel is smaler darknessThresh when you call the scream funktion but you wrote:

stop the music and quickly scream once there is light

=> that would mean music when dark.
Did I get something wrong or did you mix it up?

Well, here the changed code:

/* 
 * The calculation of the tones is made following the mathematical
 * operation:
 * timeHigh = period / 2 = 1 / (2 * toneFrequency)
 * where the different tones are described as in the table:
 * note   frequency   period   timeHigh
 * c    261 Hz    3830    1915 
 * d   294 Hz   3400   1700 
 * e   329  Hz  3038  1519 
 * f 349 Hz 2864 1432 
 * g 392 Hz 2550 1275 
 * a 440 Hz 2272 1136 
 * b 493 Hz 2028 1014
 */
 
 int speakerPin = 2;                                             // pin to use to drive speaker 
 char names[] = {'c','d','e','f','g','a','b'};                    // List of notes we want to be able to play
 int rangeOfNotes = 8;                                            
 int tones[] ={1915, 1700, 1519, 1432, 1275, 1136, 1014, 956};
 int length = 42;                                           
 char notes[] = "ccggaagffeeddcggffeedggffeedccggaagffeeddc ";    

 double beats[] = {1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4}; 
 int tempo = 300; 
 
 int lightSensor = 5;     //Analog pin Light Resistor is connected to
 int darknessThresh = 500;
 int lightLevel;
 
 bool night = true, day = true;  // for only singing and screaming once

void setup()
{
  pinMode(speakerPin,OUTPUT);
  Serial.begin(9600);
}

void Scream()
{
  digitalWrite(speakerPin, HIGH);
  delay(1500);
  digitalWrite(speakerPin,LOW);
  delay(1000);
}

 void playNote(char note, int duration)                         //plays the note "note" for the time "duration"
 {  
                                                                //play the tone corresponding to the note name
   for (int i = 0; i < rangeOfNotes; i++)
   {
   if (names[i] == note){
   playTone(tones[i], duration);
   }
   }
 }
   
 
 void playTone(int tone, int duration)
 {
   
   for (long i = 0; i < duration *1000L; i += tone * 2)     
   {
   digitalWrite(speakerPin, HIGH);
   delayMicroseconds(tone);
   digitalWrite(speakerPin, LOW);
   delayMicroseconds(tone);
   }
   
 }
 
void Sing()
{
  
   for (int i = 0; i < length; i++)                                
   { 
     
       lightLevel = analogRead(lightSensor);
       if(lightLevel > darknessThresh)   // when there is light scream and return to stop music
     {
       Scream();
      day = false;
      night = true;
      return; 
     }
     
     
       if (notes[i] == ' ')                                        
       {
         delay(beats[i] * tempo);                            
       } 
       else                                                      
       {playNote(notes[i], beats[i] * tempo);} 
    
       delay(tempo/2);                                            
   }
}

void loop()
{
  lightLevel = analogRead(lightSensor);   
  Serial.print("Light Level = ");             
  Serial.println(lightLevel); 
  
  
  
  if (night == true)    //scream once when it was day before
{
    if(lightLevel  < darknessThresh)  //dark
    {
       Scream(); 
       night = false;
       day = true;
       return;
     }
}

if (day == true)   // sing once when it was night before
{
     if(lightLevel > darknessThresh)   //light
     {
      Sing();
      day = false;
      night = true;
      return;
     }
}
}

btw you could do something like that if it is hovering around the darkness threshold :

if(lightLevel > darknessThresh +10)
if(lightLevel < darknessThresh -10)

Edit:
Did not see Pauls post before I posted. It’s quite helpfull you might wanna try on your own with the help of what he sayed before you copy my code :slight_smile: