5 minute countdown timer with warning buzzer before minute 4,1 and 0.

Hi,

Im building a 5 minute countdown timer for starting sailing races. I have been able to get the timer working perfectly however i would like to have a warning buzzer buzz once a second for the last 10 seconds of minute 4,1 and 0.

I have managed to get the buzzer to buzz once a second on the following code (using mills so not to affect the countdown timer)

int buzzerPin =  9;      // the number of the LED pin
int buzzerState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
long OnTime = 500;           // milliseconds of on-time
long OffTime = 500;          // milliseconds of off-time

void setup() 
{
  // set the digital pin as output:
  pinMode(buzzerPin, OUTPUT);      
}

void loop()
{
  // check to see if it's time to change the state of the LED
  unsigned long currentMillis = millis();
 
  if((buzzerState == HIGH) && (currentMillis - previousMillis >= OnTime))
  {
    buzzerState = LOW;  // Turn it off
    previousMillis = currentMillis;  // Remember the time
    digitalWrite(buzzerPin, buzzerState);  // Update the actual LED
  }
  else if ((buzzerState == LOW) && (currentMillis - previousMillis >= OffTime))
  {
    buzzerState = HIGH;  // turn it on
    previousMillis = currentMillis;   // Remember the time
    digitalWrite(buzzerPin, buzzerState);    // Update the actual LED
  }
}

However when i add this to the countdown timer code the buzzer will only sound once every other second in the last 10 seconds of minute 4,1 and 0.

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

int S = 00; //default timer start times
int M = 5;


int buzzer =  9;      // the number of the buzzer pin
int buzzerState = LOW;             // buzzerState used to set the buzzer
unsigned long previousMillis = 0;        // will store last time buzzer was updated
long OnTime = 200;           // milliseconds of on-time
long OffTime = 800;          // milliseconds of off-time
LiquidCrystal_I2C  lcd(0x27,2,1,0,4,5,6,7); 

void setup()
{
  // activate LCD module
  lcd.begin (16,2); // for 16 x 2 LCD module
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);
  pinMode(buzzer, OUTPUT);  //set buzzer pin as output
}

void loop()
{
  lcd.home (); // set cursor to 0,0
  lcd.print(" TIMER 5-4-1-GO"); 
  lcd.setCursor (8,1);        // go to start of 2nd line
  lcd.print(":");
S--;
 delay(1000);
  
 if(S<0)
 {
 M--;
 S=59;
 }
 if(M<0)
 {
 M=4;
 }
 
 if(M>9)
 {
 lcd.setCursor(6,1);
 lcd.print(M);
 }
 else
 {
 lcd.setCursor(6,1);
 lcd.print("0"); 
 lcd.setCursor(7,1);
 lcd.print(M);
 lcd.setCursor(8,1);
 lcd.print(":");
 }
  
 if(S>9)
 {
 lcd.setCursor(9,1);
 lcd.print(S);
 }
 else
 {
 lcd.setCursor(9,1);
 lcd.print("0"); 
 lcd.setCursor(10,1);
 lcd.print(S);
 lcd.setCursor(11,1);
 lcd.print(" ");
 }
 
 if((M==4 || M==1 || M==0) && (S<10)) //check to see if its time to activate warning buzzer 
                                      //(1 buzz every second in last 10 of min 4,1&0)
 {
 unsigned long currentMillis = millis();
 
  if((buzzerState == HIGH) && (currentMillis - previousMillis >= OnTime))
  {
    buzzerState = LOW;  // Turn it off
    previousMillis = currentMillis;  // Remember the time
    digitalWrite(buzzer, buzzerState);  // Update the actual LED
  }
  else if ((buzzerState == LOW) && (currentMillis - previousMillis >= OffTime))
  {
    buzzerState = HIGH;  // turn it on
    previousMillis = currentMillis;   // Remember the time
    digitalWrite(buzzer, buzzerState);    // Update the actual LED  
  }
 }
}

I have tried changing the "long OnTime = 200" and "long OffTime = 800" however this doesn't seem to have any effect once the buzzer code was added to the countdown timer code.

All my circuitry seems to be working find so im hoping its just something simple I've missed in the code.

Any help and suggestions appreciated

Cheers

One letter global variable names are a bad idea. It really isn't that difficult to type Hr, Min, Sec, instead.

However when i add this to the countdown timer code the buzzer will only sound once every other second in the last 10 seconds of minute 4,1 and 0.

Well, that's what you told it to do. Why is it any kind of surprise when the code does what you said?

currentMillis and previousMillis are crappy names. Some event happened that you want to record when for. The name of the variable should reflect the event, NOT the fact that millis() was used to get the value to record.

now is certainly a lot easier to type than currentMillis, and MUCH more understandable.

when (currentMillis - previousMillis) = 4 minutes turn on buzzer
when (currentMillis - previousMillis) = 3m50 seconds turn off buzzer
when (currentMillis - previousMillis) = 1 minute turn on buzzer
when (currentMillis - previousMillis) = 50s turn off buzzer
when (currentMillis - previousMillis) = 10s turn on buzzer
when (currentMillis - previousMillis) = 0 turn off buzzer
the end

I've changed what you suggested in the code.

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

int Sec = 00; //default timer start times
int Min = 5;

int buzzer =  9;      // the number of the buzzer pin
int buzzerState = LOW;             // buzzerState used to set the buzzer
unsigned long previousbuzz = 0;        // will store last time buzzer was updated
long OnTime = 200;           // milliseconds of on-time
long OffTime = 800;          // milliseconds of off-time
LiquidCrystal_I2C  lcd(0x27,2,1,0,4,5,6,7); 

void setup()
{
  // activate LCD module
  lcd.begin (16,2); // for 16 x 2 LCD module
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);
  pinMode(buzzer, OUTPUT);  //set buzzer pin as output
}

void loop()
{
  lcd.home (); // set cursor to 0,0
  lcd.print(" TIMER 5-4-1-GO"); 
  lcd.setCursor (8,1);        // go to start of 2nd line
  lcd.print(":");
Sec--;
 delay(1000);
  
 if(Sec<0)
 {
 Min--;
 Sec=59;
 }
 if(Min<0)
 {
 Min=4;
 }
 
 if(Min>9)
 {
 lcd.setCursor(6,1);
 lcd.print(Min);
 }
 else
 {
 lcd.setCursor(6,1);
 lcd.print("0"); 
 lcd.setCursor(7,1);
 lcd.print(Min);
 lcd.setCursor(8,1);
 lcd.print(":");
 }
  
 if(Sec>9)
 {
 lcd.setCursor(9,1);
 lcd.print(Sec);
 }
 else
 {
 lcd.setCursor(9,1);
 lcd.print("0"); 
 lcd.setCursor(10,1);
 lcd.print(Sec);
 lcd.setCursor(11,1);
 lcd.print(" ");
 }
 
 if((Min==4 || Min==1 || Min==0) && (Sec<10)) //check to see if its time to activate warning buzzer 
                                      //(1 buzz every second in last 10 of min 4,1&0)
 {
 unsigned long now = millis();
 
  if((buzzerState == HIGH) && (now - previousbuzz >= OnTime))
  {
    buzzerState = LOW;  // Turn it off
    previousbuzz = now;  // Remember the time
    digitalWrite(buzzer, buzzerState);  // Update the actual buzzer
  }
  else if ((buzzerState == LOW) && (now - previousbuzz >= OffTime))
  {
    buzzerState = HIGH;  // turn it on
    previousbuzz = now;   // Remember the time
    digitalWrite(buzzer, buzzerState);    // Update the actual LED  
  }
 }
}

However then the buzzer is sounding out is currently staying on for 1 whole second then remaining off for one second.
I need it to sound for 200ms then remain off for the remaining 800ms. Changing the following part of code doesn't change the duration of the buzz?

long OnTime = 200;           // milliseconds of on-time
long OffTime = 800;          // milliseconds of off-time

sorry if there are silly mistakes as i'm quite new to all this!!

I would get rid of the compound if statements. On any given pass through loop(), it is, or is not, time for the buzzer to be buzzing on and off.

If it is, it is, or is not, time to change the state. Create a new variable, of type unsigned long, in which you store now - then (the time that the buzzer has been in the current state).

If that time exceeds the on threshold, and the buzzer is on, turn it off, and record the current event's time. If that time exceeds the off threshold, and the buzzer is off, turn it one and record the current event's time.

It is easier to debug nested if statements than compound if statements.

 delay(1000);

There's your problem right there. That line essentially freezes the sketch for 1000 milliseconds (that is, one second), so it is no wonder that nothing useful gets done during that time.

odometer:

 delay(1000);

There's your problem right there. That line essentially freezes the sketch for 1000 milliseconds (that is, one second), so it is no wonder that nothing useful gets done during that time.

Use a second millis() timer to run the "decrement the second and display the new time" once every second. Run the "do the beeping if it's beep time" every time through loop() so the beep timer can do its work.

johnwasser:
Use a second millis() timer to run the "decrement the second and display the new time" once every second. Run the "do the beeping if it's beep time" every time through loop() so the beep timer can do its work.

You could do it that way, or you could do it the way I would do it.

You need to keep track of whole seconds for the timer, and you need to keep track of 0.8 second for the buzzer. This suggests to me the idea of keeping track of time to the nearest tenth of a second rather than to the nearest second.

William-Findlay:
Im building a 5 minute countdown timer for starting sailing races. I have been able to get the timer working perfectly however i would like to have a warning buzzer buzz once a second for the last 10 seconds of minute 4,1 and 0.

I am trying to understand what you mean.

Do you want the warning buzzer to start buzzing its final buzz at 4 minutes and 59 seconds after the timer starts? Or at 4 minutes and 59.2 seconds after the timer starts (so as to end exactly 5 minutes after the timer starts)? Or should this final buzz start exactly 5 minutes after the timer starts (so that it is not a warning buzz but rather a "time's up!" buzz)?

Change you delay(1000) to a test if millis - currentMillis >= 1000; currentMillis += 1000; and then in your last if, as you'll only be passing by every second, simply turn buzzer on, wait 200ms, turn buzzer off. Your (Sec<10) might want to be (Sec<=10).

Curious to know how you got on with this project, I to am wanting to do the same in timing race starts with visual digits across 2 seven segment displays. Also need to do countdowns of up to 60 minutes.

William-Findlay:
Hi,

Im building a 5 minute countdown timer for starting sailing races. I have been able to get the timer working perfectly however i would like to have a warning buzzer buzz once a second for the last 10 seconds of minute 4,1 and 0.

I have managed to get the buzzer to buzz once a second on the following code (using mills so not to affect the countdown timer)

int buzzerPin =  9;      // the number of the LED pin

int buzzerState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
long OnTime = 500;           // milliseconds of on-time
long OffTime = 500;          // milliseconds of off-time

void setup()
{
 // set the digital pin as output:
 pinMode(buzzerPin, OUTPUT);      
}

void loop()
{
 // check to see if it's time to change the state of the LED
 unsigned long currentMillis = millis();

if((buzzerState == HIGH) && (currentMillis - previousMillis >= OnTime))
 {
   buzzerState = LOW;  // Turn it off
   previousMillis = currentMillis;  // Remember the time
   digitalWrite(buzzerPin, buzzerState);  // Update the actual LED
 }
 else if ((buzzerState == LOW) && (currentMillis - previousMillis >= OffTime))
 {
   buzzerState = HIGH;  // turn it on
   previousMillis = currentMillis;   // Remember the time
   digitalWrite(buzzerPin, buzzerState);    // Update the actual LED
 }
}





However when i add this to the countdown timer code the buzzer will only sound once every other second in the last 10 seconds of minute 4,1 and 0. 



#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

int S = 00; //default timer start times
int M = 5;

int buzzer =  9;      // the number of the buzzer pin
int buzzerState = LOW;             // buzzerState used to set the buzzer
unsigned long previousMillis = 0;        // will store last time buzzer was updated
long OnTime = 200;           // milliseconds of on-time
long OffTime = 800;          // milliseconds of off-time
LiquidCrystal_I2C  lcd(0x27,2,1,0,4,5,6,7);

void setup()
{
 // activate LCD module
 lcd.begin (16,2); // for 16 x 2 LCD module
 lcd.setBacklightPin(3,POSITIVE);
 lcd.setBacklight(HIGH);
 pinMode(buzzer, OUTPUT);  //set buzzer pin as output
}

void loop()
{
 lcd.home (); // set cursor to 0,0
 lcd.print(" TIMER 5-4-1-GO");
 lcd.setCursor (8,1);        // go to start of 2nd line
 lcd.print(":");
S--;
delay(1000);
 
if(S<0)
{
M--;
S=59;
}
if(M<0)
{
M=4;
}

if(M>9)
{
lcd.setCursor(6,1);
lcd.print(M);
}
else
{
lcd.setCursor(6,1);
lcd.print("0");
lcd.setCursor(7,1);
lcd.print(M);
lcd.setCursor(8,1);
lcd.print(":");
}
 
if(S>9)
{
lcd.setCursor(9,1);
lcd.print(S);
}
else
{
lcd.setCursor(9,1);
lcd.print("0");
lcd.setCursor(10,1);
lcd.print(S);
lcd.setCursor(11,1);
lcd.print(" ");
}

if((M==4 || M==1 || M==0) && (S<10)) //check to see if its time to activate warning buzzer
                                     //(1 buzz every second in last 10 of min 4,1&0)
{
unsigned long currentMillis = millis();

if((buzzerState == HIGH) && (currentMillis - previousMillis >= OnTime))
 {
   buzzerState = LOW;  // Turn it off
   previousMillis = currentMillis;  // Remember the time
   digitalWrite(buzzer, buzzerState);  // Update the actual LED
 }
 else if ((buzzerState == LOW) && (currentMillis - previousMillis >= OffTime))
 {
   buzzerState = HIGH;  // turn it on
   previousMillis = currentMillis;   // Remember the time
   digitalWrite(buzzer, buzzerState);    // Update the actual LED  
 }
}
}





I have tried changing the "long OnTime = 200" and "long OffTime = 800" however this doesn't seem to have any effect once the buzzer code was added to the countdown timer code.

All my circuitry seems to be working find so im hoping its just something simple I've missed in the code.

Any help and suggestions appreciated

Cheers