understanding millis()

Hi everyone.
I’ve tried to avoid asking, i’m the type of guy who tries to figure it out for myself, but alas i cant take it anymore.

i have a LDR, which i have connected to a relay. the idea is for the relay to click when a certain light level is reached, hold for 6 seconds then release and go through the whole loop again.
i’ve achieved this using delay, but the spanner in my works is i have also got a LCD connected which freezes during that 6 second delay, the LCD just shows the current light level and its fine if the certain light level isn’t reached, but i need it to refresh during the delay.

I have been trying to mess around with the millis command but i cant seem to make it work with my current code.

which is here:

#include <LiquidCrystal.h>
int sensorReading = 1;
int sensorValue = 200;
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
void setup()
{
lcd.begin(16, 2);
 pinMode(6, OUTPUT);
}
void loop()
{


if (sensorReading > sensorValue)
{
 digitalWrite(6, HIGH);
 delay(6000);
}
else digitalWrite(6, LOW);

int lightReading = analogRead(sensorReading);
lcd.setCursor(0, 1);
lcd.print("Light           ");
lcd.setCursor(6, 1);
lcd.print(sensorReading);
delay(500);



}

if anyone knows how to get rid of the “delay(6000);” and put a millis command in there i will love you forever, i’ve been on this for 3 months and even had a friend who’s pretty clued up on programming look at it and between us we are stumped.

thank you all in advance
Drew

if timeFlag is false and event has started StartTime = millis() timeFlag = true Turn on device

Do things here

If timeFlag is true and millis() > startTime + 60000 Turn off device timeFlag = false

Continue program

Weedpharma

It's just amazing how hard this simple bit of code is to understand for us newb's part of that is I think that the BWOD example use's terrible variable names plus it shows a repeating timer that is great for flashing a LED but not so clear if you want to actually time something.

I still get it wrong sometimes(which has been pointed out when I've tried to help before) got it wrong here too but thankfully Weedpharma was faster and now I've saved this example sketch so I won't make that mistake again.

Correct example which I hope is easier to understand below:

unsigned long starTime = 0;     
const long interval = 1000;  // 1 second = 1000 millis       
bool timeFlag = false

void setup() {
}

void loop() {
  if(something you want to Time){
   starTime = millis();
   timeFlag = true;
   // do stuff here when timing starts
  }

  unsigned long currenTime = millis();
  if (currenTime - starTime >= interval && timeFlag == true) {
    timeFlag = false;
   // do stuff here when time is up
  }
}

Thanks for the quick replies, i was looking up timeflags when Hutkikz replied.
i tried to add your code to mine, but i think i stuffed it:

#include <LiquidCrystal.h>
int sensorReading = 1;//analog pin reading
int sensorValue = 200;
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
unsigned long starTime = 0;     
const long interval = 6000;         
bool flag = false;
void setup()
{
lcd.begin(16, 2);
pinMode(6, OUTPUT);
}
void loop()
{


if (sensorReading > sensorValue)
{starTime = millis();
flag = true;

digitalWrite(6, HIGH);
}  
unsigned long currenTime = millis();
if (currenTime - starTime >= interval && flag == true) {
  flag = false;
}else digitalWrite(6, LOW);

int lightReading = analogRead(sensorReading);
lcd.setCursor(0, 1);
lcd.print("Light           ");
lcd.setCursor(6, 1);
lcd.print(sensorReading);
delay(500);


}

i did something wrong here??
thanks guys for the help

comments in code

#include <LiquidCrystal.h>
int sensorReading = 1;//analog pin reading
int sensorValue = 200;
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
unsigned long starTime = 0;    
const long interval = 6000;        
bool flag = false;
void setup()
{
lcd.begin(16, 2);
 pinMode(6, OUTPUT);
}
void loop()
{


if (sensorReading > sensorValue)
{starTime = millis();
flag = true;

 digitalWrite(6, HIGH);
}  
 unsigned long currenTime = millis();
 if (currenTime - starTime >= interval && flag == true) {
   flag = false;
   digitalWrite(6, LOW);  // <<<< to here
 }//  else digitalWrite(6, LOW);  <<<<< moved this inside the bracket for the timing

int lightReading = analogRead(sensorReading);
lcd.setCursor(0, 1);
lcd.print("Light           ");
lcd.setCursor(6, 1);
lcd.print(sensorReading);
delay(500);


}

and Please use code tags ( the </> symbol)

To get rid of the other delay you need a second timing code with another set of variables for it.

if (sensorReading > sensorValue)

int lightReading = analogRead(sensorReading);

Those two statements do not make sense. Which pin are you reading from? How is that pin number going to be higher than 200? Why does that matter?

Why not use names that make sense. sensorValue and sensorPin make sense. sensorReading as a pin number variable does not.

weedpharma: If timeFlag is true and millis() > startTime + 60000

Close, but no cigar...

This will work most of the time, but will occasionally fail if startTime is within 6000 ms of when millis() reaches the maximum value and is about to rollover back to zero. The correct order of operations is shown in the other code suggestions on this thread:

If timeFlag is true and millis() - startTime >= 60000

Note how the order of the operations have changed, basically using subtraction rather than addition. Done in this order, when at the the boundary condition where millis() rolls over during the timed interval, the math will rollover in the same manner and the operation will still work as expected.

I suppose I should feel better that it's not just me, but I just don't get how this seemingly simple bit of code causes so many to get it wrong.

The demo Several Things at a Time is an extended example of BWoD.

…R

You do need to pick some better variables names, it seems to be confusing you a bit (part of why it wasn’t working). To give you an idea I here’s are some better names (just made them up real quick):

sensorReading to sensorInputP
sensorValue to sensorActivateVal
starTime to startTime
interval to lightInterval
flag to lightActive

As far as understanding mills() it’s easier than it seems. Pretend that millis() returns the current real time. If at the time your light is activated it is 12:20pm and you want it to last 6 minutes then you record the time activated (in this case 12:20pm) and you wait until millis()(still pretending it returns the current real time) - 12:20pm >= 6 minutes. This will happen at 12:26pm because 12:26pm - 12:20pm is 6 minutes. Hopefully that helps.

This should fix your code (I kept your variable names):
Untested, but it should work. I added some comments too:

#include <LiquidCrystal.h>
int sensorReading = 1;//analog pin reading
int sensorValue = 200;
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
unsigned long starTime = 0;    
const long interval = 6000;        
bool flag = false;
void setup()
{
    lcd.begin(16, 2);
    pinMode(6, OUTPUT);
}

void loop()
{


    //Check if sensor reading is high enough
    int lightReading = analogRead(sensorReading);
    if (lightReading > sensorValue)
    {
        //Log current time
        starTime = millis();
        flag = true;

        //Activate light
        digitalWrite(6, HIGH);
    }
    
    //When light active
    if (flag)
    {
        unsigned long currenTime = millis();
        
        //See if it has been longer than interval
        if (currenTime - starTime >= interval) 
        {
            //Turn off light and wait for activation
            flag = false;
            digitalWrite(6, LOW);  // <<<< to here
        }//  else digitalWrite(6, LOW);  <<<<< moved this inside the bracket for the timing
    }


    lcd.setCursor(0, 1);
    lcd.print("Light           ");
    lcd.setCursor(6, 1);
    lcd.print(sensorReading);
    //delay(500);


}

Hi everyone. thank you all for your help.

I'm very new to all of this, approx 5 months total, in between moving house and stuff.

My original code was pieced together using tutorials and similar projects on the net, as i was trying things i probably should have re-named variables as i went, but was more interested in getting the thing working.

to answer PaulS.

the sensorValue = 200 is the parameter when the relay clicks on,(when the light level reaches 200,the relay goes high) it isn't a pin number. The reading is taken off pin A1 i got this off an adafruit tutorial and has been working fine thus far, is this not the correct way to do this?

SRegan.

This seems to work to an extent. the relay stays constantly high until the light reading goes below 200 then it stays on for 6 seconds after that, then goes low, do i need to put a low command for pin 6 after the "digitalWrite(6,HIGH)"? does it have something to do with removing the "else" command?

i appreciate all of you for taking the time to help me. thank you so much.

it isn't a pin number

But a pin number isn't likely to be greater than 200 either.

if (sensorReading > sensorValue)

the relay stays constantly high until the light reading goes below 200 then it stays on for 6 seconds after that, then goes low, do i need to put a low command for pin 6 after the “digitalWrite(6,HIGH)”?

I’ve edited the code a bit so once the light turns on it stays on for only 6 seconds independent of what the sensor value is. However, if right when the light turns off the sensor value is > 200 than it will click right back on again. I did this by making it only check the sensor and turn on the light (and record the current time) when the light is not already on (when flag is false) by taking what used to be above the “if (flag)” and moving into an else.

Let me know if this is what you were looking to achieve. It’s possible that you might want to add a delay before the light can be re-activated.

#include <LiquidCrystal.h>
int sensorReading = 1;//analog pin reading
int sensorValue = 200;
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
unsigned long starTime = 0;    
const long interval = 6000;        
bool flag = false;
void setup()
{
    lcd.begin(16, 2);
    pinMode(6, OUTPUT);
}

void loop()
{
    
    //When light active
    if (flag)
    {
        unsigned long currenTime = millis();
        
        //See if it has been longer than interval
        if (currenTime - starTime >= interval) 
        {
            //Turn off light and wait for activation
            flag = false;
            digitalWrite(6, LOW);  // <<<< to here
        }//  else digitalWrite(6, LOW);  <<<<< moved this inside the bracket for the timing
    }
    else
    {
         //Check if sensor reading is high enough
         int lightReading = analogRead(sensorReading);
         if (lightReading > sensorValue)
         {
             //Log current time
             starTime = millis();
             flag = true;

             //Activate light
             digitalWrite(6, HIGH);
         }
    }


    lcd.setCursor(0, 1);
    lcd.print("Light           ");
    lcd.setCursor(6, 1);
    lcd.print(sensorReading);
    //delay(500);


}

http://www.gammon.com.au/blink


@drewboy: Please edit your posts, select the code, and put it between [code][/code] tags.

You can do that by hitting the “Code” icon above the posting area. It is the first icon, with the symbol: </>


Please use code tags.

Read this before posting a programming question

SRegan.

thank you so much, you have made my day.

theres a few other little tinkers i need to do, one of them is a delay after the loop, does it need to be timed from the initial currentTime or does it run off its own separate timer.

for example, if i wanted the code to wait 10 seconds, do i setup a interval and implement that into the existing timer or do i start from scratch and give it its own starting point?

thank you so much, im in your debit.

appreciate all the help from everyone, i did learn a heap about it from reading everyones suggestions. thank you all

Drew