Servo and Buzzer duration

Hi I am trying to get a continuous servo motor and buzzer to run for 2 seconds after the LDR detects a low value, however they are triggered and start running when the LDR detects something but it does not stop after 2 seconds and just keeps on running. I have attached the wiring diagram and code, please help.

edit: i realise the LDR is wired incorrectly in the diagram, i have wired it with a resistor in my project

#include <Servo.h> // Library for the servo
Servo myservo; // Create a servo object to control the servo

#define buttonPin 2
#define LDR A0
#define LED 1
#define buzzer 3

unsigned long startMillis; 
unsigned long currentMillis;
const unsigned long period = 2000; // 2 seconds

int buttonState;
bool isRunning = false;

void setup() {
  myservo.attach(9); // Attach the servo to pin 9
  pinMode(buttonPin, INPUT_PULLUP); // Set button pin as input with internal pull-up
  pinMode(LDR, INPUT); // Set LDR pin as input
  pinMode(LED, OUTPUT); // Set LED pin as output
  pinMode(buzzer, OUTPUT); // Set buzzer pin as output

  Serial.begin(9600); // Start serial communication at 9600 baud
}

void loop() {
  int ldrValue = analogRead(LDR); // Read the LDR value
  Serial.println(ldrValue); // Print the LDR value to the serial monitor

  // Check if the light level is low (LDR value below threshold) and system is not already running
  if (ldrValue < 300 && !isRunning) {
    isRunning = true; // Set running flag to true
    startMillis = millis(); // Record the start time
    myservo.write(45); // Servo spins in clockwise direction
    digitalWrite(LED, HIGH); // Turn on the LED
    playBuzzer(); // Play buzzer sound
  }

  // If the system is running, check the elapsed time
  if (isRunning) {
    currentMillis = millis();
    // If the elapsed time is greater than or equal to the period, stop everything
    if (currentMillis - startMillis >= period) {
      myservo.write(90); // Stop the servo
      digitalWrite(LED, LOW); // Turn off the LED
      noTone(buzzer); // Stop the buzzer sound
      isRunning = false; // Reset the running flag
    }
  }

  // Check if the button is pressed
  buttonState = digitalRead(buttonPin);
  if (buttonState == LOW) {
    myservo.write(135); // Servo spins in counter-clockwise direction
    delay(2000); // Wait for 2 seconds
    myservo.write(90); // Stop the servo
  }
}

void playBuzzer() {
  tone(buzzer, 1000); // Play 1000 Hz tone
  delay(100); // Wait for 100 ms
  tone(buzzer, 500); // Play 500 Hz tone
  delay(100); // Wait for 100 ms
  noTone(buzzer); // Stop any sound from the buzzer
}


void playBuzzer() {
  // Control buzzer frequency for siren effect
  if (increasing) {
    buzzerFrequency += frequencyStep;
    if (buzzerFrequency >= 1000) {
      increasing = false; // Start decreasing frequency
    }
  } else {
    buzzerFrequency -= frequencyStep;
    if (buzzerFrequency <= 500) {
      increasing = true; // Start increasing frequency
    }
  }
  tone(buzzer, buzzerFrequency); // Set the buzzer to the current frequency
}

your LDR is wired as heater, A0 will be always 1023. LED showed on wrong pin.
for buzzer better to use a driver.

#include <Servo.h> // Library for the servo
Servo myservo; // Create a servo object to control the servo

#define buttonPin 2
#define LDR A0
#define LED 4
#define buzzer 3

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 2000; // 2 seconds

int buttonState;
bool isRunning = false;
int buzzerFrequency = 500; // Start frequency for the siren sound
int frequencyStep = 10; // Step size for frequency change
bool increasing = true; // Flag for increasing or decreasing frequency

void setup() {
  myservo.attach(9); // Attach the servo to pin 9
  pinMode(buttonPin, INPUT_PULLUP); // Set button pin as input with internal pull-up
  pinMode(LDR, INPUT); // Set LDR pin as input
  pinMode(LED, OUTPUT); // Set LED pin as output
  pinMode(buzzer, OUTPUT); // Set buzzer pin as output

  Serial.begin(9600); // Start serial communication at 9600 baud
}

void loop() {
  int ldrValue = analogRead(LDR); // Read the LDR value
  Serial.println(ldrValue); // Print the LDR value to the serial monitor

  // Check if the light level is low (LDR value below threshold) and system is not already running
  if (ldrValue < 80 && !isRunning) {
    isRunning = true; // Set running flag to true
    startMillis = millis(); // Record the start time
    myservo.write(45); // Servo spins in clockwise direction
    digitalWrite(LED, HIGH); // Turn on the LED
  }

  // If the system is running, manage all components
  if (isRunning) {
    playBuzzer(); // Call playBuzzer to control the siren sound

    // If the elapsed time is greater than or equal to the period, stop everything
    if (millis() - startMillis >= period) {
      myservo.write(90); // Stop the servo
      digitalWrite(LED, LOW); // Turn off the LED
      noTone(buzzer); // Stop the buzzer sound
      isRunning = false; // Reset the running flag
    }
  }

  // Check if the button is pressed
  if (digitalRead(buttonPin) == LOW) {
    myservo.write(135); // Servo spins in counter-clockwise direction
    delay(2000); // Wait for 2 seconds
    myservo.write(90); // Stop the servo
  }
  delay(10);
}

void playBuzzer() {
  // Control buzzer frequency for siren effect
  if (increasing) {
    buzzerFrequency += frequencyStep;
    if (buzzerFrequency >= 1000)increasing = false; // Start decreasing frequency
  } else {
    buzzerFrequency -= frequencyStep;
    if (buzzerFrequency <= 500)increasing = true; // Start increasing frequency
  }
  tone(buzzer, buzzerFrequency); // Set the buzzer to the current frequency
}
1 Like

You do not reset the timers so once "period" is passed, the difference between currentMillis and startMillis will always increase.

how would i reset the timers?

After you determine the period has passed, set the variable holing the elapsed time to the current time. You are using "startMillis" for this.

Hi, @clai7

Do you understand this point here?


Before you do any code editing, you need to understand how the LDR circuit is supposed to work.
This link may help.
https://maker.pro/arduino/tutorial/how-to-use-an-ldr-sensor-with-arduino

Tom.. :smiley: :+1: :coffee: :australia:

hi tom, yes i understand the wiring diagram is wrong and i have wired it correctly i believe now, with a resistor in place

does that mean i would do like

currentMillis=startMillis

to reset the timers back to 0?

Add a debug Serial.println after you call playBuzzer ( for example printing currentMillis ) to understand what's going on...

Consider the following sketch.

/* a global variable to remember the last time (and the first time)
   we did the thing and will repeat the event every 3 seconds by
   comparing it to a timer variable, in this case, threeSecondTimer.
   In a more complex sketch, it may be helpful to declare these 
   variables locally to some function, but we'll keep it simple for
   this example. */
unsigned long lastTime = 0;
unsigned long threeSecondTimer = 3000;

void setup() {
  Serial.begin(115200);
  Serial.println("millisTimerRepeatingEvent");
  Serial.println();
}

void loop() {
  /* now that currentmillis equals millis(), 
     it will count up until 4,294,967,295 before starting over at 0 */
  unsigned long currentMillis = millis();

  if (currentMillis - lastTime > threeSecondTimer) {
    Serial.println("this gets printed every 3 seconds, or 3000 milliseconds");
    // and anything you put in this block will also run only every 3000 milliseconds
    // as long as it's non-blocking (so while() or delay() will break the precision of the 
    //  timer)
    lastTime = currentMillis;
  }
}

Yes/somewhat. A relative "zero"... the millis() counter is always increasing. Your code assigns millis() to currentMillis so you can compare the "now" time. When your period elapses, you will want to to set your new "zero" time to startMillis... so your assignment should look like this (opposite of your post):

startMillis = currentMillis // startMillis is assigned the value held by currentMillis

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.