Go Down

Topic: [QUESTION] How to use millis() function? (Read 2347 times) previous topic - next topic

Nickollas Aranha

Hello guys!

I'm new here, but I've done a lot of research through posts and doubts, but still I couldn't understand pretty much how to use the millis() function, instead of delay().

I would like to someone answer these questions:

    Let me give an example first:

Code: [Select]

unsigned long startTime = 0;
unsigned long endTime = 0;

void setup () {

// setup pins and stuffs

}

void loop () {

//Let's say i would like to blink a led after 2000 miliseconds, without using delay ()

digitalWrite (pin, HIGH); // I know pin does not exist, but it's just an example :)
endTime += 2000;
startTime = millis ();

   if (startTime > endTime) {
   digitalWrite (pin, LOW);
   endTime = 0;
   // reset millis() ?
   }
}



I would like to understand how it works now:

1 I must refresh 'startTime' variable everytime I go on loop?
2 How to 'reset' millis () ?
3 I must declare some 'currentTime' variable in order to keep millis () working?

I appreciate if someone could help!

Thanks in advance!

PaulS

Quote
1 I must refresh 'startTime' variable everytime I go on loop?

That depends on what startTime represents. Maybe you need to change it. Maybe you don't.

What does startTime mean to YOU?

Quote
2 How to 'reset' millis () ?

Forget it. How often do you reset your watch? Practically never, right? And yet you get places on time, most of the time, right?

Quote
3 I must declare some 'currentTime' variable in order to keep millis () working?

No. The clock works whether you look at it, or not.

That code you posted won't do anything useful.

Code: [Select]
endTime += 2000;
startTime = millis ();

   if (startTime > endTime) {

On every pass through loop, you increment endTime by 2000, and then want to know if startTime (now) is greater than endTime. On the first pass, it won't be, and the difference will never be less than on the first pass.

HazardsMind

#2
Mar 13, 2013, 01:17 pm Last Edit: Mar 13, 2013, 02:05 pm by HazardsMind Reason: 1
Millis() starts at the exact time the program starts. It's the internal timer for the arduino, and it can not be reset manually once started. The reason its better than delay is because, delay uses a while loop and nothing can be done until the while loop is finished. But with Millis, it runs on the arduinos clock cycles, which runs in the background, so it will allow you to do other things while its running.
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

UKHeliBob

Quote
//Let's say i would like to blink a led after 2000 miliseconds, without using delay ()

That is a very laudable ambition, but what do you mean by blink ?
Turn the LED on ?
Turn the LED off ?
Turn the LED on then off ?
Turn the LED on/off every 2 seconds ?

If you have not already done so, have a look at the BlinkWithoutDelay program in the IDE examples.  It is well commented to explain what is going on.

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

Nickollas Aranha

Hello guys, thanks for answering that soon!

Alright, let me try to explain better.

I have a webserver running on my arduino, and I would like to make an Ajax Call to set a pin ON or OFF.

The problem is that this pin could have a 'timer'... I need it to be ON for x ms, and then OFF. (x>=0)

The code works fine with delay (), but I don't like it (it's innificient), so I decided to use millis (). (well, tried to)

Let's have another example:

Code: [Select]

void setup () {
//set pins and stuffs;
}

void loop () {

//try to get client
//get HTTP Request from client
    if (HTTP_request.indexOf("ajax_call") > -1) {
    setPin (HTTP_request);
    } else {
    // show website
    }
}

void setPin (String action) {

//a little bit of string manipulation here, i will have that:
// PIN | ACTION | TIMER // i.e:
// 22 | 1 | 4000
// So, I must set pin 22 HIGH, for 4000 ms

}



So, this is the code I want to implement, how can I use millis ()?

The millis () starts running on ARDUINO setup, or it starts on SCOPE call?

If it starts by ARDUINO setup, so I must do something like:

Code: [Select]

unsigned long currentTime;
unsigned long startTime;
unsigned long endTime;

...

void loop () {
currentTime = millis ();

     if ((currentTime - startTime) > endTime) {
     // Turn off PIN;
     }

}


Is that right? If so, I would change the setPin function... but I need to know if my thought is right!

Thanks in advice!

PaulS

You need to read, understand, and, most importantly, embrace the technique outlined in the blink without delay example. It shows how to perform an action, and record when that action was performed.

Knowing that the action (turn an LED on) was performed, and when it was performed, you can determine if another action (turn the LED off) is required, and when that needs to happen.

Quote
// So, I must set pin 22 HIGH, for 4000 ms

No. You must set the pin HIGH. Then, in loop(), you look to see if the pin is HIGH, and, if so, if enough time has passed to require turning it off.

Nickollas Aranha

#6
Mar 13, 2013, 05:38 pm Last Edit: Mar 13, 2013, 05:42 pm by Nickollas Aranha Reason: 1
Thanks for answering!

The point is that i don't need the led to keep 'blinking', I need to turn it off after x ms.

I came up with this code, could you tell me if it's wrong or inefficient? (I don't have arduino right now for testing).

Code: [Select]

int ledPin;
unsigned long previousMillis = 0;
unsigned long interval = 0;
int check = 1; // Could use boolean also

void setup() {
  // set pins and stuffs    
}

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

 if (interval > 0 && check == 1) { // This because i only need to verify time if I have a TIMER
   previousMillis = currentMillis;
 } else if (interval >0) {  
       check = 0;

       if ((currentMillis - previousMillis) > interval) {
       digitalWrite(ledPin, LOW);
       interval = 0;
       check = 1;
       }
 }
 
 // Start Ethernet Connection
 if (HTTP_request.indexOf ("ajax_call") > -1) {
 setRelay (HTTP_request); // I don't really do it on my code, it's just an example
 } else {
 // send website;
 }

}

void setRelay (int pinRelay, char status, int time) {

    if (status == "1") {
        if (time > 0) { // Here I can see if the relay must stay ON for x ms
        interval = time;
        ledPin = pinRelay; // Here i could use some array to do that for more than 1 led, maybe i should create a struct... will think about it later :)
        return;
        }
        digitalWrite (pinRelay, HIGH); // Here is just a relay that doesn't have a TIMER.
    } else if (status== "0")
    digitalWrite (pinRelay, LOW); // here i don't care about timing, the relay is just going OFF.
   
}

HazardsMind

#7
Mar 13, 2013, 05:44 pm Last Edit: Mar 13, 2013, 05:46 pm by HazardsMind Reason: 1
Quote
if ((currentMillis - previousMillis) > interval) {

No, make it this,
Code: [Select]
if ((millis() - previousMillis) > interval) {
Otherwise "currentMillis - previousMillis" will always be 0, because you declaired "previousMillis = currentMillis;"

Add: actually you dont need this line anymore, "previousMillis = currentMillis;" just replace previousMillis with currentMillis in here.
Code: [Select]
if ((millis() - previousMillis) > interval) {
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

Nickollas Aranha

Hi!

I disagree with your suggestion, for those reasons:

Code: [Select]
void loop () {
  unsigned long currentMillis = millis();

  if (interval > 0 && check == 1) { // This because i only need to verify time if I have a TIMER
    previousMillis = currentMillis;
  } else if (interval >0) { 
        check = 0;

        if ((currentMillis - previousMillis) > interval) {
        digitalWrite(ledPin, LOW);
        interval = 0;
        check = 1;
        }
  }


It means, this line
Quote
previousMillis = currentMillis;
will happen only once, because of
Quote
if (interval > 0 && check == 1)


It's like 'the first run'. After that, i call
Quote
else if (interval >0) { 
        check = 0;


Well, i can remove the 'currentMillis' and use only millis (), but I'll focus on memory later! :)

Do you agree with me?

Thanks in advance!

HazardsMind

Apologies, I over looked the else statement. You do still need this,"unsigned long currentMillis = millis();" to have something the millis() can compare to.
My GitHub:
https://github.com/AndrewMascolo?tab=repositories

Arrch

So when a condition occurs, you want to light the LED for a given amount of time? Simple:

Code: [Select]
if (condition occurs)
{
 turn light on
 record lightOnTime
}

if (now minus lightOnTime is greater than our interval)
{
 turn light off
}

Nickollas Aranha

@HazardsMind
No problem mate, I appreciate your help!

@Arrch
I think my last code is doing it now, I will test it when I get home.

If someone thinks it won't work, please leave a comment!

Thanks!

Arrch


@Arrch
I think my last code is doing it now


Maybe, but it's doing it with more code than necessary.

Nickollas Aranha

Guys, hello!

Just wanted to thank you all for helping, this is working now!

I will sure have more doubts, so, keep waiting for me!

Thanks!

Go Up