Pages: [1]   Go Down
Author Topic: Using millis() instead of delay  (Read 1930 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Sr. Member
****
Karma: 1
Posts: 462
I am a amateur.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello!
I have found a technique for executing recurrent events every ms interval without delay(). I know many reasons not to use delay. I am making this into a library. You can even execute a function 4 times, and not do it again! My unfinished library version is even more flexible. But, for this to work properly, no delay() statements can be made, or it may disturb the running functions. It doesn't use interrupts.
Code:
//execute function g() every interval ms
void timer(unsigned long interval, void (*g)()){
  static unsigned long prev = 0;
  if (millis() - prev >= interval){
    g();
    prev = millis();
  }
}
//execute function g() every interval ms, times times only
void timer(unsigned long interval, void (*g)(), unsigned long times){
  static unsigned long prev = 0;
  static unsigned long counter = 0;
  if (millis() - prev >= interval && counter < times){
    g();
    prev = millis();
    counter++;
  }
}
//function to be run
void blinking(){
  static boolean state = 1;
  digitalWrite(13, state);
  state = !state;
}
void fading(){
  static byte brightness = 0;
  static int fadeAmount = 1;
  analogWrite(9, brightness);   
  brightness = brightness + fadeAmount;
  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount ;
  }     
}
void setup(){
  pinMode(13, OUTPUT);
}
void loop(){
  //blink the LED on pin 13 every 500 ms 5 times only
  timer(500, blinking, 5);
  //fade an LED on pin 9 forever...
  timer(30, fading);
}
What's your opinion on this code?
Logged


Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 208
Posts: 8856
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think it only works as expected because you are using each of the "timer()" functions only once.

If you took the '5' out of timer(500, blinking, 5); the blink would never get executed.  Every 30 mSec the second call to timer() would trigger and reset 'prev'.  The fading would happen but "millis() - prev" would never reach 500 so the blink would never happen.

You could create a timer object that keeps a separate "prev" for each timer.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Sr. Member
****
Karma: 1
Posts: 462
I am a amateur.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Actually, I tried it, and it works. I declared prev static as to not let it reset. smiley-wink I also made it into a library using class. But, there is no need to write "timer(30, fading);" 2 times in the loop, so that isn't a problem. I also did something without the extra parameter, and it works!
« Last Edit: May 13, 2012, 06:52:29 pm by dkl65 » Logged


Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 208
Posts: 8856
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

'static' just means that it keeps its value even when the function it is defined in exits.  Every caller to the function will be using the same instance of the variable.

I just tried it on an Arduino UNO with:
Code:
void loop(){
  //blink the LED on pin 13 every 500 ms forever...
  timer(500, blinking);
  //fade an LED on pin 9 forever...
  timer(30, fading);
}

For reasons I explained above the LED on pin 13 never blinked.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Sr. Member
****
Karma: 1
Posts: 462
I am a amateur.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Weird, because I modified someone's code to sweep a servo back and forth every 10 seconds to wake up a device by shaking it, and blinks led 13 at the same time. He was using delay() before.
Code:
void loop(){
  timer(10000, tipper);
  timer(500, blinking);
}
Works perfectly. But, I didn't have the second function with the extra parameter.
Quote
You could create a timer object that keeps a separate "prev" for each timer.
How to do?
If I use my library with seperate classes, will it work?
Quote
/*Multitasking
Original by Daniel Liang
This example lets you blink an LED on pin 13, and fade an LED on
pin 9 at the same time! It uses the Routine class of the Easy
library. This class uses millis() to run functions at intervals,
effectively not stopping the program, and can be used to replace
delay().
*/
#include <Easy.h> //include the Easy library
//instantiante two Routine objects
Routine routine1;
Routine routine2;
//function for fading LED on pin 9
void fading(){
  static byte brightness = 0;
  static byte fadeAmount = 1;
  analogWrite(9, brightness);   
  brightness = brightness + fadeAmount; 
  if (brightness == 0 || brightness == 255) {
    fadeAmount = -fadeAmount ; 
  }      
}
//function for blinking LED on pin 13
void blinking(){
  static boolean output = 1; //output HIGH or LOW variable
  digitalWrite(13, output);
  output = !output;
}
void setup(){
  pinMode(13, OUTPUT);
}
void loop(){
  //begin fading and blinking at the same time!
  routine1.begin(30, fading);
  routine2.begin(500, blinking);
}

« Last Edit: May 13, 2012, 07:51:08 pm by dkl65 » Logged


Western New York, USA
Offline Offline
Faraday Member
**
Karma: 36
Posts: 4326
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
What's your opinion on this code?

How does this differ in basic concept from 'Blink Without Delay' http://arduino.cc/en/Tutorial/BlinkWithoutDelay which really should be called 'Blink Without delay()' ?

Don
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 462
I am a amateur.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It is packed into a function, and can be copied to any sketch. I also made it into a library, as stated previously. I based this of Blink Without Delay. It is not only for blinking. It can be for almost anything. Even this code I uploaded does 2 actions at once!
Logged


SF Bay area
Offline Offline
Sr. Member
****
Karma: 3
Posts: 268
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I agree with John that by making prev static, you will be mixing up the usage of the two calls to timer.
You are thinking that each timer call has its "own" copy of prev that is not reset. but actually, both timer calls are using the same prev variable.

when you say "use my library in separate classes", if you meant converting your timer function by wrapping it in a class that contains timer function and creating two instances of the class, then yes it will work, as each class instance will keep its own copy of prev. The Routine class you posted does exactly that.

Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 462
I am a amateur.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Then, the library will be the best option. There are already libraries which do what I am doing, but my library has more options.
Logged


Pages: [1]   Go Up
Jump to: