Timer issue

I made this timer to activate a TIP102 on my protoshield, and then turn it off again after the time defined, but something isn’t working as espected, and I suspect the part where it is failing is where I calculate the four int’s into the millis it should wait. But am I doing something wrong there, or is the problem something else in it?

//Define the timer
int seconds     = 0;
int minutes     = 15;
int hours       = 0;
int days        = 0;

int relDelay    = 1000;   //How long delay there will be between the beep and the release of the magnet

//Digital pins
int piezoPin    = 12;    //Where the piezo is connected to
int ledPin      = 13;    //Using the on board LED for visualisation
int relayPin    = 9;     //Where the TIP102 is connected to




unsigned long waitTime = 0;
long startTime = 0;

void beep(int freq, int dur)
{
  digitalWrite(ledPin, HIGH);
  
  for(int i=0; i < dur; i++)
  {
    digitalWrite(piezoPin, HIGH);
    delayMicroseconds(freq);
    digitalWrite(piezoPin, LOW);
    delayMicroseconds(freq);
  }
  
  digitalWrite(ledPin, LOW);
}

void setup()
{
  //Set pin modes
  pinMode(piezoPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(relayPin, OUTPUT);
  
  //Calculate the waiting time
  waitTime = seconds*1000;
  waitTime += (minutes*1000)*60;
  waitTime += ((hours*1000)*60)*60;
  waitTime += (((days*1000)*60)*60)*24;
  
  if (waitTime >= 4294967295)
  {
    waitTime = 4294967294;
    beep(150, 1000); //Warn with one long beep about it shortened down
    delay(500);
  }
  
  for(int i=0; i < 2; i++) //Two beeps to tell the timer has started
  {
    beep(250, 500);
    delay(80);
  }
    
  digitalWrite(relayPin, HIGH);
  startTime = millis();
}

void loop()
{
  if ((millis() - startTime) + relDelay > waitTime)
  {
    if (waitTime < 4294967295)
    {
      waitTime = 4294967295; //Yay! You made it, lets set it to max so it won't keep beeping
        
      for(int i=0; i < 4; i++)
      {
        beep(250, 500);
        delay(80);
      }
      
      delay(relDelay); //Release delay to warn about the magnet is about to be released
      
      //Switch magnet off
      digitalWrite(relayPin, LOW);
    }
  }
}
waitTime += (((days*1000)*60)*60)*24;
if (waitTime >= 4294967295)

if waitTime gets too large for an unsigned long, the value will wrap around to a low value (like a car's odometer). It will not stay at the maximum value.

if waitTime gets too large for an unsigned long, the value will wrap around to a low value (like a car's odometer). It will not stay at the maximum value.

Yes, but that is not the problem either, that part seems to work exactly like it is intended to do (haven't tested it with the maximum possible time yet, only lower values)

But the problem is that I can define the seconds just fine, and it then runs for that amount of seconds, and releases. 60 seconds makes it wait 60 seconds, but if I define it in the minutes part (or some other), it seems to never finish...

Minute: 15 * 1000 to get the milliseconds 15000 * 60 because there are 60 seconds in one minute

Hour: 15 * 1000 = 15000 to get the milliseconds 15000 * 60 = 900000 because there are 60 seconds in one minute 900000 * 60 = 54000000 for the 60 minutes in one hour

Day: 15 * 1000 = 15000 to get the milliseconds 15000 * 60 = 900000 because there are 60 seconds in one minute 900000 * 60 = 54000000 for the 60 minutes in one hour 54000000 * 24 = 1296000000 to get the milliseconds in one day, but this is way over what a unsigned long can take

Math isn't my strong side, am I doing something wrong (I must be, wasen't the limit 39 or 49 days?) ?Or is it a totally wrong approach? I am not looking for dead accuracy, but within a few seconds would be nice. :)

//Calculate the waiting time
waitTime = seconds1000;
waitTime += (minutes
1000)60;
waitTime += ((hours
1000)*60)60;
waitTime += (((days
1000)*60)*60)*24;

Unless you indicate otherwise, for the expressions above, the compiler generates int (16 bit) multiplies. You have three choices (and some combinations)…

  1. Explicit casting…

waitTime = (unsigned long) seconds * 1000;

  1. Promotion to a larger datatype…

waitTime = seconds * 1000ul;

  1. Or use larger datatypes…

unsigned long seconds = 0;
unsigned long minutes = 15;
unsigned long hours = 0;
unsigned long days = 0;

There may be other problems in your code but forcing the multiples to 32 bit should at least get you on the right track.

There are 10006060*24 = 86 400 000 milliseconds in one day. Your wait time can be as large as 49.7102696 days.