Pages: [1]   Go Down
Author Topic: delay() in only one method  (Read 2235 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm relatively new to Arduino, but sorry if this is a basic question.

Is it possible to get a delay function to only affect one method and not stop my whole program from executing? (ie if I want one method to run every few seconds, but I need the rest of the program to continually execute)
Logged

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

delay() is a blocking delay, won't work for what you are trying to accomplish.

You can use millis() to get reasonably accurate timed activities.  Example:

Code:
unsigned int timer = millis() + 2000;

void setup(){
  Serial.begin(115200);
}

void loop(){
 
  if(millis() > timer){
    //run myRoutine every 2 seconds
    myRoutine();
    timer = millis() + 2000;
  }
 
  //Rest of program here
 
}

void myRoutine(){
  Serial.println(millis());
 
}
Logged


Arduinoville
Offline Offline
Newbie
*
Karma: 1
Posts: 26
Arduino is my strong friend
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I started using Timer1 from the Jesse Tane, http://www.arduino.cc/playground/Code/Timer1 for timing in my project. My entire code is posted in another thread on the forum if you're interested in seeing how I used it http://arduino.cc/forum/index.php/topic,50010.0.html

Matt
Logged

Sometimes things are as they appear

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 207
Posts: 12912
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can use millis() to get reasonably accurate timed activities.  Example:

Your example fails to work correctly as millis approaches the wrap.
Logged

New Hampshire
Offline Offline
God Member
*****
Karma: 17
Posts: 781
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can use millis() to get reasonably accurate timed activities.  Example:

Your example fails to work correctly as millis approaches the wrap.


Good point.  Couple minor tweaks can fix that.
1.Change the assignments to timer = millis();
2.Change the if condition to (millis() - timer > 2000)
Logged


Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 207
Posts: 12912
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
2.Change the if condition to (millis() - timer >= 2000)

 smiley-wink
« Last Edit: January 27, 2011, 11:33:17 pm by Coding Badly » Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 127
Posts: 8517
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

How about

Code:
if(millis() % 2000 == 0) {
    myRoutine();
}

Admitedly is causes some arithmatic in every loop but if there's little else to do anyway.

It will "hickup" at the wrap every 49 days but that may not be a problem.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 207
Posts: 12912
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Two additional problems with that method that make it unusable...

1. millis sometimes increments by 2 instead of 1.  If the value goes from 1999 to 2001, the then-clause is skipped.

2. If the code around the if-condition takes 1.5 milliseconds or longer to run, the then-clause may be skipped.  If the code around the if-condition takes more than 2 milliseconds to run, the then-clause will always be skipped.

But, it's good you mentioned the idea so it can be discussed.

Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 127
Posts: 8517
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
millis sometimes increments by 2 instead of 1.
Ooow, that's a gotcha I didn't know about, is that to accomodate slight mismatches in the timing, sort of a leap year adjustment.

And yes the other code can't take too long or you miss a slot until the next time.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 207
Posts: 12912
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Ooow, that's a gotcha I didn't know about, is that to accomodate slight mismatches in the timing, sort of a leap year adjustment

Exactly.

The interrupt fires 1024 times a second (when the processor is clocked at 16 MHz).  When the interrupt fires, the millis value is increment (the "1000" part of the value) and a fraction is accumulated (the "24" part of the value).  When the fraction accumulates to a full millisecond, the millis value is incremented.  One increment for the interrupt the second increment for the fraction.
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 127
Posts: 8517
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
millis sometimes increments by 2 instead of 1

OK I've been thinking about this. % will then either return 0 or 1, is that the case?

If so then

Code:
if((millis() % 2000) < 2) {
    myRoutine();
}

Should work.

______
Rob

Logged

Rob Gray aka the GRAYnomad www.robgray.com

UK
Offline Offline
Sr. Member
****
Karma: 1
Posts: 491
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm relatively new to Arduino, but sorry if this is a basic question.

Is it possible to get a delay function to only affect one method and not stop my whole program from executing? (ie if I want one method to run every few seconds, but I need the rest of the program to continually execute)

A while ago on the old forum (http://arduino.cc/forum/index.php/topic,48946.msg349959.html#msg349959) I tried to explain this sort of thing in English rather than code - maybe it will help here.

Quote
Imagine you yourself want to physically ring a bell every 30 seconds. There are two ways you could do it. In the first way you ring the bell, then set an alarm clock for 30 seconds time, go to sleep, wake up when the alarm goes off, ring the bell and repeat. You are not able to do anything in that 30 seconds waiting time except wait for the alarm to go off.

The second way you would ring the bell then look at your clock and note what time it is. Then you start getting on with doing other stuff, but look at the clock periodically to see if 30 seconds has gone by yet. If not, just carry on doing other stuff and glancing at the clock. If 30 seconds has gone by, ring the bell and make a note of the new time, then carry on as before.

The first method is equivalent to to using delay() in Arduino code, the second is equivalent to using millis() to note down when you do something and wait for a time interval to pass before you do it again.

millis() tells you how many milliseconds it's been since the Arduino was powered on or reset. So you can note down what millis() returns now, do some stuff, and when you look at millis() again subtract the first reading and it will tell you how much time has gone by.

Andrew
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 207
Posts: 12912
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

OK I've been thinking about this. % will then either return 0 or 1, is that the case?

If so then

Code:
if((millis() % 2000) < 2) {
    myRoutine();
}

Should work.

You're just going to have to give up modulus for this situation...  When millis increments by one, the then-clause fires twice in quick succession.  Take the simplest case... millis returns 1999, 2000, 2001, 20002... The condition is true for both 2000 and 2001.
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 127
Posts: 8517
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bugger, OK I'll move on smiley

_____
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Pages: [1]   Go Up
Jump to: