Millis() cannot work

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 4000;
const byte buzzer = 9;   
void setup() {
  Serial.begin(9600);  
  pinMode(ledPin, OUTPUT);
  startMillis = millis(); 

}

void loop() {
   
   currentMillis = millis();
   tone( buzzer,10);
  if (currentMillis - startMillis >= period) 
  {
    noTone(buzzer);  
    startMillis = currentMillis;  
  }
}

Hi , im try to develop a program which ask the buzzer to stop after 4 seconds. Since the delay() function will affect my other codes, so i decided to use millis() instead. However, once i run the code, the buzzer still generating the sound. Actually i did use the noTone() function to stop the buzzer from working after 4 seconds but the buzzer still make noise

noTone() is working as expected. The problem is you immediately call tone() again on the very next loop. So the buzzer only turns off for a couple microseconds, too short a time to even hear it.

Let's think about your loop function.

The first line gets the current time. The second line turns the buzzer on. Then the if statement checks to see if four seconds have passed. If the 4 seconds is up then it turns off the buzzer AND GETS A NEW START TIME. So when the loop function repeats it gets the new time, turns the buzzer on, and then checks if it has been more than 4 seconds since this new start time you just got inside the if statement last time you turned it off.

So the buzzer is only off for a few microseconds and then gets turned back on for a new 4 seconds. If you don't want that then don't set a new start time OR don't turn the buzzer back on in every pass through the loop function.

Millis() cannot work

I hope the OP is going to apologize for breaking it :)

...R

Try to modify your code slightly:

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 4000;
const byte buzzer = 9;   

bool buzz = false; //ADD THIS

void setup() {
  Serial.begin(9600); 
  pinMode(ledPin, OUTPUT);
  startMillis = millis();

}

void loop() {
   
   currentMillis = millis();
   //SOMETHING REMOVED
  if (currentMillis - startMillis >= period)
  {
    //SOMETHING ADDED
    if (buzz) tone( buzzer,10);
    else noTone(buzzer); 
    buzz = !buzz;
    startMillis = currentMillis; 
  }
}

ALRIGHT, so if I want to stop the buzzer after 4 second thn I should put the notone out of the if right? I means complety turn off

lukason96: ALRIGHT, so if I want to stop the buzzer after 4 second thn I should put the notone out of the if right? I means complety turn off

No, you only want the noTone to happen when the if is true. If you just move that line out of the if then it won't wait for the 4 seconds.

It's the line that starts the tone before the if that is the problem. That's the one turning it back on.

If you really want the buzzer to just sound once for 4 seconds and then do nothing until the Arduino is reset just put an infinite loop, e.g. while(1), after the notone(). Then it won't go back round to the top of loop and start the tone() again.

If you want something else you'll have to make it a bit clearer what exactly should happen.

Steve

It is not possible to generate tones lower than 31Hz.

https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/

slipstick: If you really want the buzzer to just sound once for 4 seconds and then do nothing until the Arduino is reset just put an infinite loop, e.g. while(1), after the notone(). Then it won't go back round to the top of loop and start the tone() again.

Steve

I would never recommend anyone to use a deadloop as sollution, in fact it might trigger a watchdog event at some point causing a reset. Instead OP should set the "tone()" in "setup()" and have loop wait 4 seconds and turn it off.

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 4000;
const byte buzzer = 9;   

bool buzz = true;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  tone( buzzer,10);
  startMillis = millis();
}

void loop() {
  currentMillis = millis();
  if (buzz && (currentMillis - startMillis >= period))
  {
    noTone(buzzer);
    buzz = false;
  }
}

Yep that's another way to do it. But since what we see is obviously just a test that will later fit into a larger program with something triggering the 4 second buzz then putting the start in setup() doesn't really help much either.

Steve