understanding millis()

greetings guys.

I'm wrapping my head around this millis function because I'm eliminating the use of delay() in my code.

/* Blink without Delay

 Turns on and off a light emitting diode (LED) connected to a digital
 pin, without using the delay() function.  This means that other code
 can run at the same time without being interrupted by the LED code.

 The circuit:
 * LED attached from pin 13 to ground.
 * Note: on most Arduinos, there is already an LED on the board
 that's attached to pin 13, so no hardware is needed for this example.

 created 2005
 by David A. Mellis
 modified 8 Feb 2010
 by Paul Stoffregen
 modified 11 Nov 2013
 by Scott Fitzgerald


 This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

// constants won't change. Used here to set a pin number :
const int waterpump =  7;      // the number of the relay pin

// Variables will change :
int waterState = HIGH;             // waterState used to set the pump

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval = 15* 60* 1000L;           // interval at which to blink (milliseconds)

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

void loop()
{

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis >= interval) {
    // save the last time you pump 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (waterState == HIGH)
      waterState = LOW;
    else
      waterState = HIGH;

    // set the LED with the ledState of the variable:
    digitalWrite(waterpump, waterState);
  }
}

I modified it from arduino blinkwithoutdelay sketch.

My pump doesn't run at all. Can anyone explain why?

*the wiring from pump to arduino is correct as my delay() code works before this.

// constants won't change : const long interval = 15* 60* 1000L;

This might not evaluate correctly, because, despite the stated result type on the left, and the L on the right, the first calculation will be 15*60.

Actually, that is not a problem, because there is no int overflow.

Your code looks OK to me. Did you manage to unplug the wire, somehow ?

Try blinking a led or writing something to Serial.print( ) to see if anything is happening.

michinyon: This might not evaluate correctly, because, despite the stated result type on the left, and the L on the right, the first calculation will be 15*60.

michinyon: Actually, that is not a problem, because there is no int overflow.

Your code looks OK to me. Did you manage to unplug the wire, somehow ?

Try blinking a led or writing something to Serial.print( ) to see if anything is happening.

hey man. the wiring is fine. i tested with this and it works.

int Pump = 7;
//int Light = 8;

void setup() {
  // put your setup code here, to run once:
   Serial.begin(9600);
   pinMode (Pump, OUTPUT);
   pinMode (Light, OUTPUT);
  // put your setup code here, to run once:

}

void loop() {
  digitalWrite(Pump,HIGH); //turn on pump
  delay(300000);
  
//  digitalWrite(Light, HIGH); //turn on light
//  delay(57600000);
  
  digitalWrite(Pump,LOW); // turn off pump
  delay (1200000);
    
//  digitalWrite(Light, LOW);
//  delay(28800000);
  // put your main code here, to run repeatedly:
}

running the blingkingwithoutdelay example works too.

Well, as I said, your code looks OK.

You are not actually trying to drive the pump directly from your arduino digital output, are you ? that won't work.

michinyon: Well, as I said, your code looks OK.

You are not actually trying to drive the pump directly from your arduino digital output, are you ? that won't work.

update: seems like the pump first runs on 15mins OFF delay. That's why I thought it wasn't working. How should i tweak this?

michinyon: Actually, that is not a problem, because there is no int overflow.

Uhm, it does... 15 * 60 *1000 = 900000. Int can only be 65535. So 15 * 60 * 1000 will become 48032. So you need to make the first const match the unsigned long => 15UL * 60 *1000

So you want to have the pump running the first 15 minutes? Add the digitalWrite to setup. Also check out the rest of the small changes.

/* Blink without Delay-edit


 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

// constants won't change. Used here to set a pin number :
const int WaterpumpPin =  7;      // the number of the relay pin **better name

// Variables will change :
bool waterState = HIGH;             // waterState used to set the pump **bool is okay

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated 

// constants won't change :
const unsigned long Interval = 15UL * 60* 1000;           // interval at which to blink (milliseconds) **First const need to match the unsigned long

void setup() {
  // set the digital pin as output:
  pinMode(WaterpumpPin, OUTPUT);
  digitalWrite(WaterpumpPin, waterState); //**this makes it turn on at start

}

void loop()
{

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis >= Interval) {
    // save the last time you pump
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    waterState = !waterState; //Shorter/easier to read
    /*
    if (waterState == HIGH)
      waterState = LOW;
    else
      waterState = HIGH;
    */

    // set the LED with the ledState of the variable:
    digitalWrite(WaterpumpPin, waterState);
  }
}

Uhm, it does... 15 * 60 *1000 = 900000. Int can only be 65535. So 15 * 60 * 1000 will become 48032. So you need to make the first const match the unsigned long => 15UL * 60 *1000

I don't think so.

15 * 60 will be treated as an int, and the answer will be 900

The second multiplication will be 900 * 1000L , an int x a long, and the result will be a long, a positive long, which should have no trouble being assigned to an unsigned long on the LHS of the assignment.

And if, for some reason, the compiler attempts to do this calculation from the other end, which would be legal because multiplication is associative, then it would be an int x a long, which is long, x another int, which is still a long.

You are right! I forgot to do it in steps, by bad.

But I hope the TS will now understand the need for the L of UL postfix. And by assigning it to the first const you know it's always right. Because the fact it works out this time is pure luck.

Thanks guys.

I added a light and another condition.

Am i doing this right?

#define ONESEC (1000UL)
#define ONEMIN (60*ONESEC)
#define ONEHOUR (60*ONEMIN)

const int pump = 7;
const int light = 8;

//Variables will change
bool pumpState = HIGH;
bool lightState = HIGH;

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0; // will store the last time it was updated

//constant's wont change :
const unsigned long intervalLight = ( 16 * ONEHOUR);
const unsigned long intervalPumpOn = (10 * ONEMIN);
const unsigned long intervalPumpOff = (4 * ONEHOUR);

void setup() {
  Serial.begin(9600);
  pinMode (pump, OUTPUT);
  pinMode (light, OUTPUT);
  digitalWrite(pump, pumpState);
  digitalWrite(light, lightState);
}

void loop()
{
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= intervalLight) {
    // save the last time light on
    previousMillis = currentMillis;
    //if light is off turn it on and vice vera
    lightState = !lightState;
    digitalWrite(light, lightState);
  }
  //updatePump();

  if (currentMillis - previousMillis >= intervalPumpOn) {
    //save the last time the pump on
    previousMillis = currentMillis;
    
    pumpState = HIGH;
    digitalWrite(pump, pumpState);
  }

  if (currentMillis - previousMillis <= intervalPumpOff) {
    previousMillis = currentMillis;
    
    pumpState = LOW;
    digitalWrite( pump, pumpState);
  }

}

trying to run the pump 10mins on and 4 hours off

It looks as if you need 4 sets of timer variables, one for your pump on period, one for your pump off period, one for your light on period and one for your light off period. (Only three if your light on period = your light off period. It's not clear from your code)

unsigned long previousMillisPumpOn;
unsigned long previousMillisPumpOff;
unsigned long previousMillisLightOn;
unsigned long previousMillisLightOff;

Instead of 4 lots of currentMillis, just use millis(), which is, of course the current number of milliseconds since the Arduino was powered up or reset.

Also, look up 'State machine'. It may make your code simpler.

The code below might help.... I've put the BlinkWithoutDelay functionality in a function called bwod() and which is repeated as many times as needed as bwod2() etc. Those are called from loop(). Right at the top of the sketch, the on- and off-times are defined for each LED; they may all differ from one another.

(Meantime, I have re-done all of this as a library, which I'll post this weekend after a bit more testing....)

/* Blink without Delay in a function

 by JimboZA.... this one puts bwod code in a function and
 allows for differing off and on times
 and for that to be with 3x independent LEDs

 Turns on and off a light emitting diode(LED) connected to a digital  
 pin, without using the delay() function.  This means that other code
 can run at the same time without being interrupted by the LED code.

 The circuit:
 * LED2 attached from pin 12, 14, 15 to ground.


 adapted from:
 created 2005
 by David A. Mellis
 modified 8 Feb 2010
 by Paul Stoffregen

 This example code is in the public domain.


 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

// constants won't change. Used here to 
// set pin numbers:
const int ledPin =  12;      // the number of the LED pin
const int led2Pin =  14;
const int led3Pin =  15;

// Variables will change:
//led1
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval;           // interval at which to blink (milliseconds)
long onTime=890;
long offTime=105;

//led2

int led2State = LOW;             // ledState used to set the LED
long previousMillis2 = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval2;           // interval at which to blink (milliseconds)
long onTime2=275;
long offTime2=260;

//led3

int led3State = LOW;             // ledState used to set the LED
long previousMillis3 = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval3;           // interval at which to blink (milliseconds)
long onTime3=125;
long offTime3=1575;



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

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  //and bwod() is where all the bwod stuff is done
  bwod();
  bwod2();
  bwod3();
}




void bwod()
{

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
    {
      ledState = HIGH;
      interval=onTime;
    }
    else
    {
      ledState = LOW;
      interval=offTime;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
} //end bwod


void bwod2()
{

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis2 = millis();

  if(currentMillis2 - previousMillis2 > interval2) {
    // save the last time you blinked the LED 
    previousMillis2 = currentMillis2;   

    // if the LED is off turn it on and vice-versa:
    if (led2State == LOW)
    {
      led2State = HIGH;
      interval2=onTime2;
    }
    else
    {
      led2State = LOW;
      interval2=offTime2;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(led2Pin, led2State);
  }
}//end bwod2

void bwod3()
{

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis3 = millis();

  if(currentMillis3 - previousMillis3 > interval3) {
    // save the last time you blinked the LED 
    previousMillis3 = currentMillis3;   

    // if the LED is off turn it on and vice-versa:
    if (led3State == LOW)
    {
      led3State = HIGH;
      interval3=onTime3;
    }
    else
    {
      led3State = LOW;
      interval3=offTime3;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(led3Pin, led3State);
  }
}//end bwod3