need help with millis() rollover for growduino!!!

Hello, I made a sofware for my growduino project. I've tried many many things, but I really can't go over that millis rollover problem (Which occur about 15-20 hours after the program start) I would really appreciate if any of you could help me with that, so I can stop killing my plants!!! Thanks for your help!

Here is the software:

 //By Martin Rioux 
    
    //GENERAL
    unsigned long lastmillis = 0;  
    
    //PUMP (WATER PUMP)
    int pump_pin = 3;         
    unsigned long last_pump_on = 0;
    unsigned long last_pump_off = 0;
    unsigned long pump_delay = 300000;       //PUMP TIME OFF
    unsigned long pump_duration = 300000;    //PUMP TIME ON
    
    //LED (STATUS LED, BLINK EVERY SEC)
    int led_pin = 2;          
    unsigned long last_led_on = 0;
    unsigned long last_led_off = 0;
    unsigned long led_duration = 1000;  //LED BLINK DELAY (1 SEC ON, 1 SEC OFF)

    
    void setup()
    {
    //PUMP SETUP
    pinMode(pump_pin, OUTPUT);    
    last_pump_on = 0;
    last_pump_off = 0;
   
    //LED SETUP
    pinMode(led_pin, OUTPUT);    
    last_led_on = 0;
    last_led_off = 0 ;
    
    //ALLOW TO SEE IF (lastmillis > millis()) WORK PROPERLY
    lastmillis = 99999999;     
    }

    void loop()
    {   

    // RESET TIMER WHEN ROLLOVER
    if (lastmillis > millis())    
    {
    last_pump_on = 0;
    last_pump_off = 0; 
    last_led_on = 0;
    last_led_off = 0;
    lastmillis = 0;
    digitalWrite(pump_pin, HIGH);
    digitalWrite(led_pin, HIGH);
    }                          
    
    //GENERAL CYCLE START
    lastmillis = millis();     
   
    //PUMP OFF -> ON
    if(digitalRead(pump_pin) == LOW) 
    {
    if ((lastmillis - last_pump_off) > pump_delay)
    {
    digitalWrite(pump_pin, HIGH);
    last_pump_on = lastmillis;
    }
    }
    
    //PUMP ON -> OFF
    if(digitalRead(pump_pin) == HIGH)
    {
    if ((lastmillis - last_pump_on) > pump_duration)
    {
    digitalWrite(pump_pin, LOW);
    last_pump_off = lastmillis;
    }
    }                          
    
    //LED OFF -> ON
    if(digitalRead(led_pin) == LOW)               
    {
    if ((lastmillis - last_led_off) > led_duration)
    {
    digitalWrite(led_pin, HIGH);
    last_led_on = lastmillis;
    }
    }                          
    
    //LED ON -> OFF  
    if(digitalRead(led_pin) == HIGH)               
    {
    if ((lastmillis - last_led_on) > led_duration)
    {
    digitalWrite(led_pin, LOW);
    last_led_off = lastmillis;
    }
    }                          
    } //void loop()

First, millis() rolls over after about 49 days, not 15-20 hours.

Second, the fact that millis() rolls over should, if used correctly, not be a problem.

The largest value that lastmillis can hold, since it is an unsigned long, is 4,294,967,295, which is far larger than 99,999,999.

What, specifically, seems to be the problem?

Whatever code I use, the blinking led stop blinking (as the pump do) in on or off state after 15-20 hours.

"pump_pin" is declared as an output - why are you reading it?

Can't I do that????

I read the pin to see if it is on or off, so I can turn it off or on.

I've never made C++ before going on the arduino (as you can see) so there is many things I don't know about.

But my present problem is only about the fact that after 15-20 hours, everything stop in their current state (may it be on or off). My code is pretty simple, so if someone could read it quickly and tell me I haven't factored, I would be really happy.

Thanks for your answers!!

Ok, thanks AWOL, I just understood what you meant. That was really newbish of me and I'll fix that. But I know (and I'm sure) that this is not the origin of the problem. Thanks again!

Strange things can happen when you try to read from an output pin. I'd suggest, since you are only trying to remind yourself (when reading the pump and led pins) whether you have turned them on or off, you simpy keep track of whether they are on or off.

When you have done that, and removed the initialization of lastmillis to a strange value, let us know whether that solved the problem. If not, we'll look at the code again.

At this time, nothing jumps out at me as the cause of your problem. But, the code will be much shorter when you keep track of whether you have turned the various pins off or on, and it will be easier to see where the bug is hiding.

If necessary, for testing purposes, change the initial value is lastmillis to something very small, like 10 minutes (360000). If the value of lastmillis is related to the problem, the code should crash in 10 minutes, rather than 15 hours.

Ok, thanks. I'll try to fix what I can and then wait to see if it crash or not. Se you in 1-3 days!!!

Which version of the Arduino environment are you using? the 10-20hour rollover problem was fixed somewhere around version 15, IIRC, and there may have been hiccoughs since then as well, but it SHOULD work in the latest code.

When you mean environment, you mean the sofware??? I use the version 18 of the arduino software and my board is the arduino mega, when it was just released. Here is what I changed in my sofware. Let's hope it will work!

  //By Martin Rioux
   
       //GENERAL
   unsigned long lastmillis = 0;  
   
       //PUMP (WATER PUMP)
   int pump_pin = 3;
   int pump_on = 0; // 0=OFF, 1=ON   
   unsigned long last_pump_on = 0;
   unsigned long last_pump_off = 0;
   unsigned long pump_delay = 300000;       //PUMP TIME OFF
   unsigned long pump_duration = 300000;    //PUMP TIME ON
   
       //LED (STATUS LED, BLINK EVERY SEC)
   int led_pin = 2;         
   int led_on = 0; 
   unsigned long last_led_on = 0;
   unsigned long last_led_off = 0;
   unsigned long led_duration = 1000;  //LED BLINK DELAY (1 SEC ON, 1 SEC OFF)

   
   void setup()
   {
       //PUMP SETUP
   pinMode(pump_pin, OUTPUT);    
   last_pump_on = 0;
   last_pump_off = 0;

       //LED SETUP
   pinMode(led_pin, OUTPUT);    
   last_led_on = 0;
   last_led_off = 0 ; 
   }

  
   void loop()
   {  

       // RESET TIMER WHEN ROLLOVER
   if (lastmillis > millis())    
     {
     last_pump_on = 0;
     last_pump_off = 0;
     last_led_on = 0;
     last_led_off = 0;
     lastmillis = 0;
     digitalWrite(pump_pin, HIGH);
     digitalWrite(led_pin, HIGH);
     }                          
   
       //GENERAL CYCLE START
   lastmillis = millis();    

       //PUMP OFF -> ON
   if(pump_on == 0)
     {
     if ((lastmillis - last_pump_off) > pump_delay)
       {
       digitalWrite(pump_pin, HIGH);
       pump_on = 1;
       last_pump_on = lastmillis;
       }
     }
   
       //PUMP ON -> OFF
   if(pump_on == 1)
     {
     if ((lastmillis - last_pump_on) > pump_duration)
       {
       digitalWrite(pump_pin, LOW);
       pump_on = 0;
       last_pump_off = lastmillis;
       }
     }                          
   
       //LED OFF -> ON
   if(led_on == 0)              
     {
     if ((lastmillis - last_led_off) > led_duration)
       {
       digitalWrite(led_pin, HIGH);
       led_on = 1;
       last_led_on = lastmillis;
       }
     }                          
   
       //LED ON -> OFF  
   if(led_on == 1)              
     {
     if ((lastmillis - last_led_on) > led_duration)
       {
       digitalWrite(led_pin, LOW);
       led_on = 0;
       last_led_off = lastmillis;
       }
     }                          
   }   //void loop()
  // RESET TIMER WHEN ROLLOVER
  if (lastmillis > millis())    
  {
  last_pump_on = 0;
  last_pump_off = 0;
  last_led_on = 0;
  last_led_off = 0;
  lastmillis = 0;
  digitalWrite(pump_pin, HIGH);
  digitalWrite(led_pin, HIGH);
  }

Your lack of indenting leaves a lot be desired, as does your failure to use the # button when posting code.

That aside, though, I'm curious as to why you turn the pump and led on when millis() rolls over. I'd understand turning them off, even though it is not really necessary to do anything when millis() rolls over.

I made the reset section like that just to make sure it won't do two OFF cycle in a row, since overwatering is preferable over underwatering. This is the only reason.

And thanks for the # tip, I'll use it next time!!!

And thanks for the # tip, I'll use it next time!!!

That would be appreciated. You can modify your existing posts, too. Select the code, hit the # button, and Save. The code will be in the nice gray boxes that have scroll bars (when needed).

Thanks! And as you can see, I've indented my code too.

15 hours since I lunched the program. Everything run fine so far!

22h45 after the beginning of the software, I noticed that the pump stopped in the OFF state. Same for the LED. Now I really don't understand what's going on....

Here is my last code again :

//By Martin Rioux
   
       //GENERAL
   unsigned long lastmillis = 0;  
   
       //PUMP (WATER PUMP)
   int pump_pin = 3;
   int pump_on = 0; // 0=OFF, 1=ON   
   unsigned long last_pump_on = 0;
   unsigned long last_pump_off = 0;
   unsigned long pump_delay = 300000;       //PUMP TIME OFF
   unsigned long pump_duration = 300000;    //PUMP TIME ON
   
       //LED (STATUS LED, BLINK EVERY SEC)
   int led_pin = 2;         
   int led_on = 0; 
   unsigned long last_led_on = 0;
   unsigned long last_led_off = 0;
   unsigned long led_duration = 1000;  //LED BLINK DELAY (1 SEC ON, 1 SEC OFF)

   
   void setup()
   {
       //PUMP SETUP
   pinMode(pump_pin, OUTPUT);    
   last_pump_on = 0;
   last_pump_off = 0;

       //LED SETUP
   pinMode(led_pin, OUTPUT);    
   last_led_on = 0;
   last_led_off = 0 ; 
   }

  
   void loop()
   {  

       // RESET TIMER WHEN ROLLOVER
   if (lastmillis > millis())    
     {
     last_pump_on = 0;
     last_pump_off = 0;
     last_led_on = 0;
     last_led_off = 0;
     lastmillis = 0;
     digitalWrite(pump_pin, HIGH);
     digitalWrite(led_pin, HIGH);
     }                          
   
       //GENERAL CYCLE START
   lastmillis = millis();    

       //PUMP OFF -> ON
   if(pump_on == 0)
     {
     if ((lastmillis - last_pump_off) > pump_delay)
       {
       digitalWrite(pump_pin, HIGH);
       pump_on = 1;
       last_pump_on = lastmillis;
       }
     }
   
       //PUMP ON -> OFF
   if(pump_on == 1)
     {
     if ((lastmillis - last_pump_on) > pump_duration)
       {
       digitalWrite(pump_pin, LOW);
       pump_on = 0;
       last_pump_off = lastmillis;
       }
     }                          
   
       //LED OFF -> ON
   if(led_on == 0)              
     {
     if ((lastmillis - last_led_off) > led_duration)
       {
       digitalWrite(led_pin, HIGH);
       led_on = 1;
       last_led_on = lastmillis;
       }
     }                          
   
       //LED ON -> OFF  
   if(led_on == 1)              
     {
     if ((lastmillis - last_led_on) > led_duration)
       {
       digitalWrite(led_pin, LOW);
       led_on = 0;
       last_led_off = lastmillis;
       }
     }                          
   }   //void loop()

May it be due to the fact that I'm using an Arduino MEGA??

Also I am running the arduino with a 9v powersuply (it is not connected to a computer)

Here is another code I tried, unsuccessfully. Maybe I'll help you understand what I am missing...

#define lmillis() ((long)millis())

//Const
int pumpPin = 3;        
int pledPin = 2;
int ledPin = 1;
unsigned long pumpOFF = 25; // 25 en minutes
unsigned long pumpON = 5; // 5 en minutes

//Var
unsigned long pumpDelay = lmillis();
unsigned long ledDelay = lmillis();
bool pumpStatus = 0;
bool ledStatus = 0;


void setup()
{
      //Pins
      pinMode(pumpPin, OUTPUT);
      pinMode(ledPin, OUTPUT);
      pinMode (pledPin, OUTPUT); 
      digitalWrite(pumpPin, HIGH);
      digitalWrite(pledPin, HIGH);
      digitalWrite(ledPin, LOW);

      //Put the time in millis
      pumpOFF=pumpOFF*1000*60;
      pumpON=pumpON*1000*60;

}

void loop() 
{
////////////////////////////////////////// Pump section
      if (timeout(pumpDelay))
      {
            if (pumpStatus) {  //Stop pump
                  pumpDelay = lmillis() + pumpOFF;
                  digitalWrite(pumpPin, LOW);
                  digitalWrite(pledPin,LOW);
                  pumpStatus = 0;
            }
            else { //Start pump
                  pumpDelay = lmillis()+pumpON;
                  digitalWrite(pumpPin, HIGH);
                  digitalWrite(pledPin,HIGH);
                  pumpStatus = 1;
            }
      }
////////////////////////////////////////// Led section
      if (timeout(ledDelay))
      {
            if (ledStatus) { //Stop led
                  digitalWrite(ledPin,LOW);
                  ledStatus = 0;
            }
            else { //Start led
                  digitalWrite(ledPin,HIGH);
                  ledStatus = 1;
            }
            ledDelay = lmillis() + 1000;
      }

// Delay so the arduino takes it easy
      delay(1000);
}

boolean timeout(unsigned long interval)
{
      return lmillis()-(long)interval > 0;
}

define lmillis() ((long)millis())

To work correctly at the rollover, the value needs to be unsigned. Do not typecast the return value to signed.

This doesn't explain the problem you're currently having but it would explain very erratic behaviour after running about 25 days.

unsigned long pumpDelay = lmillis(); unsigned long ledDelay = lmillis();

These two should be initialized in setup. millis may not be ready for use when they're initialized in this fashion.

Back to the code that worked for 22 hours and 45 minutes. The 9V power supply is not a little 9V battery is it?

What happens if you have the Mega connected to the computer, and each time you toggle the LED or pump pin, you write the operation performed and the current value of millis() to the serial monitor? What are the last few value printed?