0
Offline
Newbie
Karma: 0
Posts: 14
Arduino rocks
|
 |
« on: January 27, 2011, 11:59:05 am » |
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
God Member
Karma: 13
Posts: 776
There are 10 kinds of people, those who know binary, and those who don't.
|
 |
« Reply #1 on: January 27, 2011, 12:14:14 pm » |
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: 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
|
|
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 129
Posts: 10379
|
 |
« Reply #3 on: January 27, 2011, 01:56:14 pm » |
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
God Member
Karma: 13
Posts: 776
There are 10 kinds of people, those who know binary, and those who don't.
|
 |
« Reply #4 on: January 27, 2011, 03:06:33 pm » |
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
Shannon Member
Karma: 129
Posts: 10379
|
 |
« Reply #5 on: January 27, 2011, 03:13:15 pm » |
2.Change the if condition to (millis() - timer >= 2000) 
|
|
|
|
« Last Edit: January 27, 2011, 11:33:17 pm by Coding Badly »
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Online
Tesla Member
Karma: 75
Posts: 6970
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #6 on: January 27, 2011, 09:51:14 pm » |
How about 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
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 129
Posts: 10379
|
 |
« Reply #7 on: January 28, 2011, 12:37:59 am » |
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
Online
Tesla Member
Karma: 75
Posts: 6970
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #8 on: January 28, 2011, 02:25:34 am » |
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
|
|
|
|
|
Global Moderator
Dallas
Offline
Shannon Member
Karma: 129
Posts: 10379
|
 |
« Reply #9 on: January 28, 2011, 03:09:24 am » |
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
Online
Tesla Member
Karma: 75
Posts: 6970
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #10 on: January 28, 2011, 04:50:15 am » |
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 if((millis() % 2000) < 2) { myRoutine(); }
Should work. ______ Rob
|
|
|
|
|
Logged
|
|
|
|
|
UK
Offline
Sr. Member
Karma: 0
Posts: 491
|
 |
« Reply #11 on: January 28, 2011, 06:20:28 am » |
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. 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
Shannon Member
Karma: 129
Posts: 10379
|
 |
« Reply #12 on: January 28, 2011, 01:07:10 pm » |
OK I've been thinking about this. % will then either return 0 or 1, is that the case? If so then 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
Online
Tesla Member
Karma: 75
Posts: 6970
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #13 on: January 28, 2011, 06:47:56 pm » |
Bugger, OK I'll move on  _____ Rob
|
|
|
|
|
Logged
|
|
|
|
|
|