millis() Timer Trouble

Hello all!

I'm new to programming ARDUINO's, and I'm having trouble figuring out how to get a timer working using millis().

The function I'm trying to achieve:

When pushButton is pressed led-13 turns on. (easy enough)
While pushButton is being pressed a timer starts.
After timer reaches a previously set time, and the pushButton is still pressed, a buzzer sounds.
That's it

I've looked at a few different tutorials using millis(), but none of them quite use it in the way I'm trying to. What happens is after I press and release the button it will wait the set time then the buzzer goes off, but the timer should start and the buzzer should sound while the button is STILL pressed.

int light = 13;
int pushButton = 2;
int buzzer = 12;
unsigned long timer;

void setup () {
Serial.begin (9600);
pinMode(light, OUTPUT);
pinMode(pushButton, INPUT);
pinMode(buzzer, OUTPUT);
}

void loop () {

int buttonState = digitalRead(pushButton);

if(buttonState == 1){
digitalWrite(light, HIGH);
Serial.println("pressed");
timer = millis();
}
else{
digitalWrite(light, LOW);
Serial.println("NOT PRESSED");
}

if(millis() - timer > 3000){
digitalWrite(buzzer, HIGH);
}
else{
digitalWrite(buzzer, LOW);
}

}

I've tried every different variation I could find or think of. Assistance would be most appreciated. Thanks!

delayedBuzzer.ino (718 Bytes)

if(flag ==1 && millis() - timer > 3000){
You need to add a flag variable to disable this when the button is not pushed.

I added a flag to disable the timer code when the button isn't pressed, but it still doesn't work with the button pressed either. Not sure if I did it right.

int light = 13;
int pushButton = 2;
int buzzer = 12;
unsigned long timer;

;

void setup () {
Serial.begin (9600);
pinMode(light, OUTPUT);
pinMode(pushButton, INPUT);
pinMode(buzzer, OUTPUT);
}

void loop () {
boolean flag = false;
int buttonState = digitalRead(pushButton);

if(buttonState == 1){
digitalWrite(light, HIGH);
Serial.println("pressed");
timer = millis();
flag = true;
}
else{
digitalWrite(light, LOW);
Serial.println("NOT PRESSED");
}

if(flag == true && millis() - timer > 3000){
digitalWrite(buzzer, HIGH);
}
else{
digitalWrite(buzzer, LOW);
}

}

You've got another problem here. As loop repeats, as long as the button is held down you'll set timer to millis on each pass of loop. So it can't possibly be 3 seconds later as long as the button stays pressed. You need to set timer to millis once when the button first becomes pressed. Have a look at the "state change example" in the IDE for some inspiration on how to do that.

Try this, I am sure there are many other ways:

int light = 13;
int pushButton = 2;
int buzzer = 12;
unsigned long timer;
boolean flag = false;  

void setup () 
{
  Serial.begin (9600);
  pinMode(light, OUTPUT);
  pinMode(pushButton, INPUT_PULLUP);
  pinMode(buzzer, OUTPUT);
}

void loop () 
{
  int buttonState = digitalRead(pushButton);

  if(buttonState == HIGH){
    digitalWrite(light, HIGH);
    Serial.println("pressed");
    if (flag == false)
    {
      timer = millis();
      flag = true;
    }
  }
  else
  {
    digitalWrite(light, LOW);
    Serial.println("NOT PRESSED");
    flag = false;
  } 

  if(flag == true && millis() - timer > 3000)
  {
    digitalWrite(buzzer, HIGH);
  } 
  else
  {
    digitalWrite(buzzer, LOW);
  }

}

incidentally using both of your suggestions I figured it out. Although I ran yours LarryD it works as well, and it's a bit simpler than what I came up with. It seems like you got it to work using "INPUT_PULLUP"? I'm not sure how that works, but it did the trick in this case :slight_smile:

This is what I came up with:

int light = 13;
int pushButton = 2;
int buzzer = 12;
unsigned long timer;
int lastBS = 0;
boolean flag = false;

void setup () {
Serial.begin (9600);
pinMode(light, OUTPUT);
pinMode(pushButton, INPUT);
pinMode(buzzer, OUTPUT);
}

void loop () {

int buttonState = digitalRead(pushButton);

if(buttonState != lastBS){
if(buttonState == HIGH){
timer = millis();
}
}
lastBS = buttonState;

if(buttonState == HIGH){
digitalWrite(light, HIGH);
Serial.println("pressed");
flag = true;
}else{
digitalWrite(light, LOW);
Serial.println("NOT PRESSED");
}

if(buttonState == LOW){
flag = false;
}

if(flag == true && millis() - timer > 3000){
digitalWrite(buzzer, HIGH);
}else{
digitalWrite(buzzer, LOW);
}

}

INPUT_PULLUP prevents inputs from floating.
You may not need it if your switch is wired a certain way.
Read Nick's discussion here:

Question, why is it necessary to use a flag in this sketch?

.

If I didn't use a flag the way I did, the light would turn on after the timer was up whether the button was pressed or not.

if(flag == true && millis() - timer > 3000){
digitalWrite(buzzer, HIGH);
}else{
digitalWrite(buzzer, LOW);
}

This will only run if the timer is up && the button it still currently pressed (the way mine was set up).

Larry D, I see now what you did. Much cleaner. I used the flag to check whether the button was pressed, but you also have the flag resetting the timer once when pressed.

If I didn't use a flag the way I did, the light would turn on after the timer was up whether the button was pressed or not.

Good!

else
{
digitalWrite(light, LOW);
Serial.println("NOT PRESSED");
flag = false; // <<< Once you let the button go, cancel timing
}
. . . .

if(flag == true && millis() - timer > 3000) // <<< if flag is false, don't do this any more
. . . .